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