`
JBossWeek
  • 浏览: 79805 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

jBPM jPDL 3.2用户指南:第3章教程

阅读更多

作者:JBossWeek http://blog.csdn.net/JBossweek email:jbossweek AT gmail.com

版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息

这个教程将展示jpdl中基本的流程构造块和管理运行时执行的API使用。

该教程将通过一系列的示例进行展示。每个例子都集中展示一个特定的专题,并提供了大量的注释。这些例子也可以在jBPM下载包的src/java.examples目录中找到。

最好的学习方法就是创建一个工程,然后在例子的基础上通过不同的改动来体验。

对于eclipse用户,开始之前请先下载jbpm-3.0-[version].zip并解压缩,然后选择"File" --> "Import..." --> "Existing Project into Workspace",单击"Next",选择jBPM根目录单击"Finish"。这样就将jbpm.3工程导入到工作空间。在 src/java.examples/目录中,可以找到教程的例子。打开这些例子后,可以通过"Run" --> "Run As..." --> "JUnit Test"运行。

jBPM包括一个图形化设计器工具,可以用来编制例子中的XML。图形化设计器的下载说明请参看Section 2.1, "Downloadables Overview"。该教程不需要使用流程设计器工具。

3.1. Hello World 示例

流程定义是一个有向图,由节点和转换组成。Hello world流程有三个节点。为了理解这些如何组合在一起,我们将从一个简单的流程开始,并且不使用流程设计器。下面的图给出了hello world流程的图形化表示:

Figure 3.1.  hello world 流程图

 

public void testHelloWorldProcess() {

 

  // 该方法展示了流程定义和它的一次执行。该流程定义有3个节点:

 

  // 没有名称的start-state,一个状态's'和名为'end'的end-state。  

 

  // 下面的代码行将xml文本解析成ProcessDefinition。

 

  // ProcessDefinition是java 对象,它是流程的正规描述。

 

ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(				

                

 

    "<process-definition>" +

 

    "  <start-state>" +

 

    "    <transition to='s' />" +

 

    "  </start-state>" +

 

    "  <state name='s'>" +

 

    "    <transition to='end' />" +

 

    "  </state>" +

 

    "  <end-state name='end' />" +

 

    "</process-definition>"

 

  );

 

 

  // 下面的代码创建流程定义的一个执行

 

  ProcessInstance processInstance = 

 

      new ProcessInstance(processDefinition);

 

 

  //创建以后,流程实例有一个主执行路径(=the root token)。			

 

  Token token = processInstance.getRootToken();

 

 

  //主执行路径停留在流程定义的start-state上			

 

  assertSame(processDefinition.getStartState(), token.getNode());

 

 

  // 让我们开始执行,执行将通过缺省转换离开start-state			

 

  token.signal();

 

 

  // signal方法直到流程执行进入一个等待状态才会阻塞			

            

 

  // 流程执行已经进入第一个等待状态's'。因此现在主执行路径停留在状态's'			

 

  assertSame(processDefinition.getNode("s"), token.getNode());

 

 

  // 让我们再发送一个signal,流程将继续执行,通过缺省转换离开状态's'			

 

  token.signal(); 

 

 

  // 现在signal方法将会返回,因为流程实例已经进入end-state			

 

  assertSame(processDefinition.getNode("end"), token.getNode());

 

}

3.2. 数据库示例

在等待状态能够将流程执行持久保存到数据库是jBPM的一个基本特性。下面的例子将演示如何将流程实例保存到Jbpm数据库。这个例子也给出了可能需要使用持久化特性的环境。不同的用户代码片段都单独创建了方法,例如web应用中的代码片段用于启动流程并将执行持久化保存到数据库,然后消息驱动bean的用户代码片段从数据库加载流程实例继续执行。

关于jBPM持久化更详细的信息请参看Chapter 7, Persistence

 

public class HelloWorldDbTest extends TestCase {

 

 

  static JbpmConfiguration jbpmConfiguration = null; 

 

  static {

 

 

// 例子中给出的配置文件可以在'src/config.files'中找到。

 

// 通常配置信息使用资源文件'jbpm.cfg.xml'进行设置,

 

// 但是这里我们将通过XML字符串传递配置信息			

            

 

// 首先,静态创建JbpmConfiguration。

 

// 一个JbpmConfiguration可以用于系统中所有的线程,

 

// 这是采用静态方式创建它的原因。			

 

    jbpmConfiguration = JbpmConfiguration.parseXmlString(

 

      "<jbpm-configuration>" +

 

 

      // jbpm-context机制将jbpm核心引擎与jbpm引用环境的服务分离			

 

      "  <jbpm-context>" +

 

      "    <service name='persistence' " +

 

      "             factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" + 

 

      "  </jbpm-context>" +

 

 

      // jbpm用到的所有资源文件也在jbpm.cfg.xml中引用			

 

      "  <string name='resource.hibernate.cfg.xml' " +

 

      "          value='hibernate.cfg.xml' />" +

 

      "  <string name='resource.business.calendar' " +

 

      "          value='org/jbpm/calendar/jbpm.business.calendar.properties' />" +

 

      "  <string name='resource.default.modules' " +

 

      "          value='org/jbpm/graph/def/jbpm.default.modules.properties' />" +

 

      "  <string name='resource.converter' " +

 

      "          value='org/jbpm/db/hibernate/jbpm.converter.properties' />" +

 

      "  <string name='resource.action.types' " +

 

      "          value='org/jbpm/graph/action/action.types.xml' />" +

 

      "  <string name='resource.node.types' " +

 

      "          value='org/jbpm/graph/node/node.types.xml' />" +

 

      "  <string name='resource.varmapping' " +

 

      "          value='org/jbpm/context/exe/jbpm.varmapping.xml' />" +

 

      "</jbpm-configuration>"

 

    );

 

  }

 

 

  public void setUp() {

 

    jbpmConfiguration.createSchema();

 

  }

 

 

  public void tearDown() {

 

    jbpmConfiguration.dropSchema();

 

  }

 

 

  public void testSimplePersistence() {

 

 

// 在下面的3个方法调用之间,所有数据将通过数据库传递。

 

// 在单元测试中,这3个方法依次执行,因为我们希望测试一个完整流程的场景。

 

// 但是在实际情况中,这些方法分别响应不同的服务器请求。			

            

 

// 因为使用的是清空的内存数据库,所以首先需要部署流程。

 

// 在实际应用中,流程开发人员只需要部署一次就可以了。			

 

deployProcessDefinition();

 

 

// 假设需要在web应用中当用户提交form时启动一个流程实例(=流程执行)			

 

processInstanceIsCreatedWhenUserSubmitsWebappForm();

 

 

// 然后,当接收到异步消息时执行将继续			

 

    theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();

 

  }

 

 

  public void deployProcessDefinition() {

 

// 这个测试展示流程定义和它的一个执行。流程定义有三个节点:

 

// 没有名称的start-state,状态's'和名为'end'的end-state。			

 

    ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(

 

      "<process-definition name='hello world'>" +

 

      "  <start-state name='start'>" +

 

      "    <transition to='s' />" +

 

      "  </start-state>" +

 

      "  <state name='s'>" +

 

      "    <transition to='end' />" +

 

      "  </state>" +

 

      "  <end-state name='end' />" +

 

      "</process-definition>"

 

);

 

 

// 查找上面配置的pojo persistence context生成器			

 

    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

    try {

 

 

    // 将流程定义部署到数据库			

 

      jbpmContext.deployProcessDefinition(processDefinition);

 

    } finally {

 

      // 关闭pojo persistence context,包括将插入的流程定义sql语句flush到数据库			

 

      jbpmContext.close();

 

    }

 

  }

 

 

  public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {

 

// 这个方法中的代码可能放在struts-action或者JSF managed bean中			

            

 

// 查找上面配置的pojo persistence context生成器			

 

    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

    try { 

 

      GraphSession graphSession = jbpmContext.getGraphSession();

 

 

      ProcessDefinition processDefinition = 

 

          graphSession.findLatestProcessDefinition("hello world");

 

 

      // 通过从数据库获取processDefinition,

 

      // 我们可以像hello world例子(它没有提供持久化)那样创建流程定义的一个执行			

 

      ProcessInstance processInstance = 

 

          new ProcessInstance(processDefinition);

 

 

      Token token = processInstance.getRootToken(); 

 

      assertEquals("start", token.getNode().getName());

 

 

     // 让我们开始执行流程			

 

      token.signal();

 

 

      // 现在流程停留在状态's'			

 

      assertEquals("s", token.getNode().getName());

 

 

      // 现在processInstance已经保存在数据库中。因此流程执行的当前状态也保存到数据库中			

 

      jbpmContext.save(processInstance);

 

 

      // 下面的方法将从数据库中取回流程实例,并发送另外一个外部的signal让流程继续执行			

            

 

} finally {

 

      // 关闭pojo persistence context			

 

      jbpmContext.close();

 

    }

 

  }

 

 

  public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {

 

 

// 这个方法里的代码可以是消息驱动bean的内容			

 

//查找上面配置的pojo persistence context生成器			

 

    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

try {

 

 

      GraphSession graphSession = jbpmContext.getGraphSession();

 

 

      // 首先,需要从数据库取回流程实例。获得当前操作流程实例的方法有几种。

 

      // 在简单的test case中最容易的方法就是查询流程实例的整个列表。

 

      // 它应该只有一个返回值。因此让我们从查找流程定义开始			

 

      ProcessDefinition processDefinition = 

 

          graphSession.findLatestProcessDefinition("hello world");

 

 

      // 现在,查找这个流程定义的所有流程实例			

 

      List processInstances = 

 

          graphSession.findProcessInstances(processDefinition.getId());

 

 

      // 我们知道在单元测试环境中,只有一个执行。

 

      // 在实际应用中,processInstanceId可以从到达的消息内容中获取,

 

      // 也可以通过用户选择得到			

 

      ProcessInstance processInstance = 

 

          (ProcessInstance) processInstances.get(0);

 

 

      // 现在,我们可以继续执行。注意,

 

      // processInstance将signal委托给执行的主路径(=the root token)			

 

      processInstance.signal();

 

 

      // 发送signal以后,我们知道流程执行应该进入end-state			

 

      assertTrue(processInstance.hasEnded());

 

 

      // 现在,可以更新数据库中执行的状态			

 

      jbpmContext.save(processInstance);

 

 

} finally {

 

      // 关闭pojo persistence context			

 

      jbpmContext.close();

 

    }

 

  }

 

}

3.3. Context 示例: 流程变量

在流程的执行过程中,流程变量包含流程的上下文信息。流程变量与java.utilMap类似,java.utilMap将名称映射成值,流程变量则将名称映射成java对象。流程变量将作为流程实例的一部分进行持久化。为了简单,这个例子没有实用持久化,只展示了操作流程变量 API的使用,。

关于流程变量的更多信息,请参看Chapter 10, Context

 

// 这个例子也从hello world流程开始,没有对hello world流程作任何修改

 

ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(

 

  "<process-definition>" +

 

  "  <start-state>" +

 

  "    <transition to='s' />" +

 

  "  </start-state>" +

 

  "  <state name='s'>" +

 

  "    <transition to='end' />" +

 

  "  </state>" +

 

  "  <end-state name='end' />" +

 

  "</process-definition>"

 

);

 

 

ProcessInstance processInstance =

 

  new ProcessInstance(processDefinition);

 

 

// 从流程实例获取用于操作流程变量的context instance			

 

ContextInstance contextInstance = 

 

  processInstance.getContextInstance();

 

 

// 在流程离开start-state之前,在流程实例的context设置一些流程变量			

 

contextInstance.setVariable("amount", new Integer(500));

 

contextInstance.setVariable("reason", "i met my deadline");

 

 

// 从现在开始,这些变量将于流程实例关联在一起。

 

// 现在可以使用这里演示的API在用户代码中访问这些流程变量。

 

// 作为流程实例的一部分,它们也存储在数据库中			

 

processInstance.signal();

 

 

// 变量可以通过contextInstance访问			

 

assertEquals(new Integer(500), 

 

             contextInstance.getVariable("amount"));

 

assertEquals("i met my deadline", 

 

             contextInstance.getVariable("reason"));

3.4. 任务分配示例

在下面的例子里,将演示如何将任务分配给用户。因为jBPM工作流引擎与组织机构模型之间是分离的,采用表达式语言来计算任务actor的局限性太大。因此,需要通过指定AssignmentHandler的实现来计算任务的actor。

 

public void testTaskAssignment() {

 

 

  // 下面演示的流程基于hello world流程,只是将状态节点替换成任务节点。

 

  // JPDL中的任务节点表示一个等待状态,并生成在流程继续执行之前必须完成的任务

 

  ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(

 

    "<process-definition name='the baby process'>" +

 

    "  <start-state>" +

 

    "    <transition name='baby cries' to='t' />" +

 

    "  </start-state>" +

 

    "  <task-node name='t'>" +

 

    "    <task name='change nappy'>" +

 

    "      <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" +

 

    "    </task>" +

 

    "    <transition to='end' />" +

 

    "  </task-node>" +

 

    "  <end-state name='end' />" +

 

    "</process-definition>"			

 

            

 

  );

 

 

  // 创建流程定义的执行			

 

  ProcessInstance processInstance = 

 

      new ProcessInstance(processDefinition);

 

  Token token = processInstance.getRootToken();

 

 

  // 让我们开始执行流程,执行通过缺省转换离开start-state			

 

  token.signal();

 

 

  // signal方法将会阻塞直到流程执行进入等待状态。这个例子里是任务节点。			

 

  assertSame(processDefinition.getNode("t"), token.getNode());

 

 

  // 当执行进入任务节点,将会创建'change nappy'任务,

 

  // 并且调用NappyAssignmentHandler确定应该将任务分配给谁。

 

  // NappyAssignmentHandler返回'papa'			

            

 

  // 在实际环境中,任务应该使用org.jbpm.db.TaskMgmtSession中的方法从数据库中获取。

 

  // 因为不希望在这个例子里引入持久化方面的复杂性,

 

  // 所以我们只操作流程实例的第一个任务实例(我们知道在测试环境中只有一个)			

 

  TaskInstance taskInstance = (TaskInstance)  

 

      processInstance

 

        .getTaskMgmtInstance()

 

        .getTaskInstances()

 

        .iterator().next();

 

 

  // 现在,我们检查taskInstance是否确实分配给了'papa'			

 

  assertEquals("papa", taskInstance.getActorId() );

 

 

  // 现在,我们假设'papa'已经完成任务,并把任务标记为已经完成			

 

  taskInstance.end();

 

 

  // 因为这是最后(仅有的)一个任务,完成这个任务将触发流程实例的继续执行			

 

  assertSame(processDefinition.getNode("end"), token.getNode());

 

}

3.5. 定制action 示例

Action是将java定制代码绑定到jBPM流程的一种机制。Action可以与自身的节点关联(如果它们在流程的图形化表示中相关联),也可以与事件关联,例如转移、离开节点或者进入节点。在这些情况中,Action虽然不是图形化表示的一部分,但是在运行流程执行过程中激发该事件时它们仍将被执行。

我们将从例子中使用的action实现MyActionHandler开始。该action handler实现没有完成任何具体的工作,它仅仅将boolean变量isExecuted设置为true。isExecuted是静态变量,因而既可以在该action handler中访问,也可以在确认isExecuted值的action中访问。

关于Action更多的信息,请参看Section 9.5, "Actions"

 

// MyActionHandler表示在Jbpm流程执行过程中可能执行一些用户代码的类			

 

public class MyActionHandler implements ActionHandler {

 

 

  // 在每次测试之前(setUp中),成员变量isExecuted被设置为false			

 

  public static boolean isExecuted = false;  

   

 

  // 这个action将成员变量isExecuted设置为true,			

 

  public void execute(ExecutionContext executionContext) {

 

    isExecuted = true;

 

  }

 

}

前面已经提到,在每次测试之前,我们将静态变量MyActionHandler.isExecuted的值设置为false。

 

  // 每次测试都从将静态成员变量isExecuted值设置为false开始			

 

 

  public void setUp() {

 

    MyActionHandler.isExecuted = false;

 

  }

我们将从一个transition上的action开始。

 

public void testTransitionAction() {

 

 

// 下面的流程是hello world流程的变体,

 

// 在从状态's'到end-state的transition中增加了一个action。

 

// 这个测试的目的是演示将java代码集成到jbpm流程中是如何的容易			

 

    ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(

 

      "<process-definition>" +

 

      "  <start-state>" +

 

      "    <transition to='s' />" +

 

      "  </start-state>" +

 

      "  <state name='s'>" +

 

      "    <transition to='end'>" +

 

      "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +

 

      "    </transition>" +

 

      "  </state>" +

 

      "  <end-state name='end' />" +

 

      "</process-definition>"

 

);

 

 

// 让我们开始执行流程			

 

    ProcessInstance processInstance = 

 

      new ProcessInstance(processDefinition);

 

 

// 下面的signal将引起执行离开start state进入状态's'			

 

processInstance.signal();

 

 

// 这里我们确认MyActionHandler还没有执行			

 

assertFalse(MyActionHandler.isExecuted);

 

 

// 并且执行的主路径停留在状态's'			

 

    assertSame(processDefinition.getNode("s"), 

 

               processInstance.getRootToken().getNode());

 

 

// 紧接着的signal调用将触发root token执行。

 

// Token经过transition,其中的action将被执行

 

processInstance.signal();

   

 

// 这里将会看到在调用signal方法的过程中MyActionHandler已经被执行			

 

    assertTrue(MyActionHandler.isExecuted);

 

  }

下面的例子将展示同一个action,但是现在将action分别放在enter-node和 leave-node的事件上。注意与transition只有一个事件不同,节点拥有不止一个类型的事件。因此只能将action设置到节点的事件元素上。

 

ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(

 

  "<process-definition>" +

 

  "  <start-state>" +

 

  "    <transition to='s' />" +

 

  "  </start-state>" +

 

  "  <state name='s'>" +

 

  "    <event type='node-enter'>" +

 

  "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +

 

  "    </event>" +

 

  "    <event type='node-leave'>" +

 

  "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +

 

  "    </event>" +

 

  "    <transition to='end'/>" +

 

  "  </state>" +

 

  "  <end-state name='end' />" +

 

  "</process-definition>"

 

);

 

 

ProcessInstance processInstance = 

 

  new ProcessInstance(processDefinition);

 

 

assertFalse(MyActionHandler.isExecuted);

 

 

// 下面的signal将引起执行离开start state进入状态's'。

 

// 进入状态's'后,action将被执行			

            

 

processInstance.signal();

 

assertTrue(MyActionHandler.isExecuted);

   

 

// 让我们重置MyActionHandler.isExecuted			

            

 

MyActionHandler.isExecuted = false;

   

 

// 下面的signal将触发执行离开状态's'。因此流程将会继续执行			

 

processInstance.signal();

assertTrue(MyActionHandler.isExecuted);

 

分享到:
评论
2 楼 lycrystal818 2011-11-02  
正在学习中,谢谢你的总结,太及时了
1 楼 afadgaeg 2008-12-29  
好文章,顶一顶

相关推荐

    jbpm jpdl 帮助文档pdf版

    根据提供的文件信息,我们...以上是基于给定的文件信息整理出的主要知识点,覆盖了jBPM和jpdl的基本概念、安装部署、教程案例等多个方面。通过这些内容的学习,可以帮助读者更好地理解和掌握jBPM和jpdl的相关技术细节。

    jBPM-JPDL v3.2环境部署——发布到Tomcat + MySQL

    - `lib`:jBPM所需依赖的第三方库 - `doc`:API文档和用户指南 - `designer`:包含Eclipse插件,用于辅助jBPM开发 - `server`:预配置的基于JBoss的jBPM控制台和示例 **5. 安装Eclipse与jBPM插件** 虽然Eclipse不是...

    JBoss jBPM jPDL中文指南

    ### JBoss jBPM jPDL中文指南知识点详解 #### 一、引言 JBoss jBPM(Java Business Process Management)是一个开源的工作流引擎,主要用于实现业务流程管理和任务协调。jPDL(jBPM Process Definition Language)...

    jBPM4.3用户指南

    ### jBPM4.3用户指南关键知识点解析 #### 一、导言 **1.1 许可证与最终用户许可协议** - **LGPL(GNU Lesser General Public License)**: 这是一种自由软件许可协议,允许用户自由地运行、研究、共享以及修改...

    JBPM-v3.2-userguide

    列出JBPM依赖的第三方库及其作用。 #### 5.4 Web应用 描述如何部署JBPM控制台Web应用。 #### 5.5 企业架构 探讨JBPM在企业级架构中的位置和作用。 ### 六、配置 #### 6.1 配置属性 列举JBPM运行所需的主要配置...

    JBPM工作流开发指南v10-20070706.doc

    JBPM工作流开发指南v10-20070706.doc 是一份详细的学习文档,主要针对那些想要深入理解并使用JBPM工作流引擎的开发者。JBPM(Java Business Process Management)是一个开源的工作流管理系统,它允许开发者设计、...

    JBPM工作流开发指南

    三、学习JPDL 11 3.1 、简介 11 3.2 、流程版本(Version) 11 3.3 、流程定义 12 3.3.1 process-definition(流程定义) 12 3.3.2 node(自动节点) 13 3.3.3 start-state(开始状态) 13 3.3.4 end-state(结束节点) 14 ...

    jbpm 工作流开发指南

    JBPM工作流开发指南 JBPM,全称Java Business Process Management,是一款基于Java的企业级工作流管理系统,由JBoss组织开发并开源。它提供了一套完整的解决方案,用于设计、执行和管理业务流程,使得开发者能够...

    JBPM 开发指南

    ### JBPM 开发指南知识点概览 #### 一、概述 **JBPM** 是一个完全由 Java 语言编写的开源工作流管理系统,以其强大的可扩展性和灵活性而著称。JBPM 的持久化层采用了 Hibernate 技术,这使得它能够支持 Hibernate ...

    JBPM4工作流应用开始指南.rar

    41 2.9.5 导入和使用范例 41 2.10 例程:jBPM HelloWorld 43 2.11 小结 45 第3章 使用jBPM图形化流程设计器(GPD)设计流程 46 3.1 创建一个新流程 47 3.2 编辑流程定义源 49 3.3 例程:设计一个“复杂的”业务流程 ...

    jbpm运行环境配置

    除了这两个核心包,还有一些第三方jar包,它们存放在lib目录下,如dom4j、hibernate、antlr等,这些都是jbpm运行所必需的。值得注意的是,jdbc驱动jar不在这些包中,需要单独下载,具体取决于你打算使用的数据库类型...

    JBPM开发指南word版本

    本开发指南将引导你了解并掌握JBPM的基础知识,包括如何创建和管理业务流程。 一、概述 JBPM是一个基于Java的业务流程管理系统,它支持BPMN(Business Process Model and Notation)标准,使得非技术人员也能理解和...

    jbpm帮助文档(中文带源码)

    这个文档是JBPM的开发指南,旨在帮助开发者理解和应用JBPM进行工作流开发。 一、概述 JBPM的核心功能是通过JPDL(JBoss Process Definition Language)来定义和管理业务流程。JPDL是一种XML格式的语言,用于描述...

Global site tag (gtag.js) - Google Analytics