这个教程将展示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"。该教程不需要使用流程设计器工具。
流程定义是一个有向图,由节点和转换组成。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());
}
在等待状态能够将流程执行持久保存到数据库是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();
}
}
}
在流程的执行过程中,流程变量包含流程的上下文信息。流程变量与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"));
在下面的例子里,将演示如何将任务分配给用户。因为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());
}
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);
分享到:
相关推荐
根据提供的文件信息,我们...以上是基于给定的文件信息整理出的主要知识点,覆盖了jBPM和jpdl的基本概念、安装部署、教程案例等多个方面。通过这些内容的学习,可以帮助读者更好地理解和掌握jBPM和jpdl的相关技术细节。
- `lib`:jBPM所需依赖的第三方库 - `doc`:API文档和用户指南 - `designer`:包含Eclipse插件,用于辅助jBPM开发 - `server`:预配置的基于JBoss的jBPM控制台和示例 **5. 安装Eclipse与jBPM插件** 虽然Eclipse不是...
### JBoss jBPM jPDL中文指南知识点详解 #### 一、引言 JBoss jBPM(Java Business Process Management)是一个开源的工作流引擎,主要用于实现业务流程管理和任务协调。jPDL(jBPM Process Definition Language)...
### jBPM4.3用户指南关键知识点解析 #### 一、导言 **1.1 许可证与最终用户许可协议** - **LGPL(GNU Lesser General Public License)**: 这是一种自由软件许可协议,允许用户自由地运行、研究、共享以及修改...
列出JBPM依赖的第三方库及其作用。 #### 5.4 Web应用 描述如何部署JBPM控制台Web应用。 #### 5.5 企业架构 探讨JBPM在企业级架构中的位置和作用。 ### 六、配置 #### 6.1 配置属性 列举JBPM运行所需的主要配置...
JBPM工作流开发指南v10-20070706.doc 是一份详细的学习文档,主要针对那些想要深入理解并使用JBPM工作流引擎的开发者。JBPM(Java Business Process Management)是一个开源的工作流管理系统,它允许开发者设计、...
三、学习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,全称Java Business Process Management,是一款基于Java的企业级工作流管理系统,由JBoss组织开发并开源。它提供了一套完整的解决方案,用于设计、执行和管理业务流程,使得开发者能够...
### JBPM 开发指南知识点概览 #### 一、概述 **JBPM** 是一个完全由 Java 语言编写的开源工作流管理系统,以其强大的可扩展性和灵活性而著称。JBPM 的持久化层采用了 Hibernate 技术,这使得它能够支持 Hibernate ...
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 例程:设计一个“复杂的”业务流程 ...
除了这两个核心包,还有一些第三方jar包,它们存放在lib目录下,如dom4j、hibernate、antlr等,这些都是jbpm运行所必需的。值得注意的是,jdbc驱动jar不在这些包中,需要单独下载,具体取决于你打算使用的数据库类型...
本开发指南将引导你了解并掌握JBPM的基础知识,包括如何创建和管理业务流程。 一、概述 JBPM是一个基于Java的业务流程管理系统,它支持BPMN(Business Process Model and Notation)标准,使得非技术人员也能理解和...
这个文档是JBPM的开发指南,旨在帮助开发者理解和应用JBPM进行工作流开发。 一、概述 JBPM的核心功能是通过JPDL(JBoss Process Definition Language)来定义和管理业务流程。JPDL是一种XML格式的语言,用于描述...