3.2 数据库示例
jBPM的特性之一就是在流程等待状态时,拥有把流程的执行持久化到数据库中的能力。下面的例子将向你展示怎样存储一个流程实例到数据库,例子中还会出现上下文。分开的方法被用来创建不同的用户代码,例如,一段代码在web应用中启动一个流程并且持久化执行到数据库,稍后,由一个消息驱动bean从数据库中加载流程实例并且恢复它的执行。
有关jBPM持久化的更多信息可以在“第7章 持久化”找到。
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-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应用中当用户提交一个表单时我们起动一个流程
// 实例(=流程执行)…
processInstanceIsCreatedWhenUserSubmitsWebappForm();
// 然后,一个异步消息到达时继续执行。
theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
}
public void deployProcessDefinition() {
// 这个测试展示了一个流程定义以及流程定义的执行。
// 这个流程定义有3个节点:一个没有命名的开始状态,
// 一个状态“s”,和一个名称为“end”的结束状态。
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持久化上下文创建器。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
// 部署流程定义到数据库中。
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
// 关闭pojo持久化上下文。这包含激发(flush)SQL语句把流程
// 定义插入到数据库。
jbpmContext.close();
}
}
public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {
// 本方法中的代码可以被放在struts的actiong中,或JSF管理
//的bean中。
//查找在上面所配置的pojo持久化上下文创建器。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
GraphSession graphSession = jbpmContext.getGraphSession();
ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition("hello world");
// 使用从数据库中获取的流程定义可以创建一个流程定义的执行
// 就象在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);
// 以后我们可以从数据库再取回流程实例,并且通过提供另外一个
// 信号来恢复流程执行。
} finally {
// 关闭pojo持久化上下文。
jbpmContext.close();
}
}
public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {
// 本方法中的代码可以作为消息驱动bean的内容。
// 查找在上面所配置的pojo持久化上下文创建器。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
GraphSession graphSession = jbpmContext.getGraphSession();
// 首先,我们需要从数据库中取回流程实例。
// 有几个可选方法来分辨出我们在这里所要处理的流程实例。
// 在这个简单的测试中,最容易的方式是查找整个流程实例列表,
// 这里它应该只会给我们一个结果。
// 首先,让我们查找流程定义。
ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition("hello world");
// 现在我们搜索这个流程定义的所有流程实例。
List processInstances =
graphSession.findProcessInstances(processDefinition.getId());
// 因为我们知道在这个单元测试中只有一个执行。
// 在实际情况中, 可以从所到达的信息内容中提取processInstanceId
// 或者由用户来做选择。
ProcessInstance processInstance =
(ProcessInstance) processInstances.get(0);
// 现在我们可以继续执行。注意:processInstance 将委托信号
// 到主执行路径(=根令牌)。
processInstance.signal();
// 在这个信号之后,我们知道流程执行应该到达了结束状态。
assertTrue(processInstance.hasEnded());
// 现在我们可以更新数据库中的执行状态。
jbpmContext.save(processInstance);
} finally {
// 关闭pojo持久化上下文。
jbpmContext.close();
}
}
}
转载于:https://blog.51cto.com/youxue/346826