第 2 章 教程
研究以下教程,了解如何在 JPDL 中使用基本 进程构造。本教程还演示了通过应用程序编程接口管理运行时执行的方法。
本教程中的示例可在 J114 下载软件包中找到(位于
src/java.examples
子目录中)。
注意
红帽建议在此刻创建项目。然后,您可以自由试验并创建每个示例的不同。
首先,下载并安装 J114。
Dan 包括一个图形化设计器工具,用于编写示例中显示的 XML。您可以在 Downloadables Overview 部分找到图形设计器的下载说明。您不需要图形化设计器工具来完成本教程。
2.1. "hello World" 示例 复制链接链接已复制到粘贴板!
复制链接链接已复制到粘贴板!
进程定义 是一个 指示的图形,由节点和转换组成。
Hello World
进程定义有三个这些节点。(最好通过调查此简单流程而无需使用 设计器工具 )了解这些组件如何适合。 下图显示了 Hello World
进程的图形表示:
图 2.1. Hello World Process Graph
public void testHelloWorldProcess() { // This method shows a process definition and one execution // of the process definition. The process definition has // 3 nodes: an unnamed start-state, a state 's' and an // end-state named 'end'. // The next line parses a piece of xml text into a // ProcessDefinition. A ProcessDefinition is the formal // description of a process represented as a java object. 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>" ); // The next line creates one execution of the process definition. // After construction, the process execution has one main path // of execution (=the root token) that is positioned in the // start-state. ProcessInstance processInstance = new ProcessInstance(processDefinition); // After construction, the process execution has one main path // of execution (=the root token). Token token = processInstance.getRootToken(); // Also after construction, the main path of execution is positioned // in the start-state of the process definition. assertSame(processDefinition.getStartState(), token.getNode()); // Let's start the process execution, leaving the start-state // over its default transition. token.signal(); // The signal method will block until the process execution // enters a wait state. // The process execution will have entered the first wait state // in state 's'. So the main path of execution is now // positioned in state 's' assertSame(processDefinition.getNode("s"), token.getNode()); // Let's send another signal. This will resume execution by // leaving the state 's' over its default transition. token.signal(); // Now the signal method returned because the process instance // has arrived in the end-state. assertSame(processDefinition.getNode("end"), token.getNode()); }
public void testHelloWorldProcess() {
// This method shows a process definition and one execution
// of the process definition. The process definition has
// 3 nodes: an unnamed start-state, a state 's' and an
// end-state named 'end'.
// The next line parses a piece of xml text into a
// ProcessDefinition. A ProcessDefinition is the formal
// description of a process represented as a java object.
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>"
);
// The next line creates one execution of the process definition.
// After construction, the process execution has one main path
// of execution (=the root token) that is positioned in the
// start-state.
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
// After construction, the process execution has one main path
// of execution (=the root token).
Token token = processInstance.getRootToken();
// Also after construction, the main path of execution is positioned
// in the start-state of the process definition.
assertSame(processDefinition.getStartState(), token.getNode());
// Let's start the process execution, leaving the start-state
// over its default transition.
token.signal();
// The signal method will block until the process execution
// enters a wait state.
// The process execution will have entered the first wait state
// in state 's'. So the main path of execution is now
// positioned in state 's'
assertSame(processDefinition.getNode("s"), token.getNode());
// Let's send another signal. This will resume execution by
// leaving the state 's' over its default transition.
token.signal();
// Now the signal method returned because the process instance
// has arrived in the end-state.
assertSame(processDefinition.getNode("end"), token.getNode());
}
2.2. 数据库示例 复制链接链接已复制到粘贴板!
复制链接链接已复制到粘贴板!
xmvn 的基本功能之一是能够在等待状态时使数据库进程的执行
保持有效
。下一示例演示了此功能,将进程实例存储在 lsblk 数据库中。
它的工作原理是为不同部分用户代码创建单独的
方法
。例如,Web 应用中的一组用户代码启动一个进程,并在数据库中"持久性"执行。之后,消息驱动的 bean 加载该进程实例并恢复它的执行。
在这里,为不同的用户代码创建单独的
方法
。例如,Web 应用中的某个代码启动一个进程,并在数据库中"持久性"执行。之后,消息驱动的 bean 加载进程实例并恢复执行它。
注意
有关 持久性的更多信息,请参阅 第 4 章 Persistence 。
public class HelloWorldDbTest extends TestCase { static JbpmConfiguration jbpmConfiguration = null; static { // An example configuration file such as this can be found in // 'src/config.files'. Typically the configuration information // is in the resource file 'jbpm.cfg.xml', but here we pass in // the configuration information as an XML string. // First we create a JbpmConfiguration statically. One // JbpmConfiguration can be used for all threads in the system, // that is why we can safely make it static. jbpmConfiguration = JbpmConfiguration.parseXmlString( "<jbpm-configuration>" + // A jbpm-context mechanism separates the jbpm core // engine from the services that jbpm uses from // the environment. "<jbpm-context>"+ "<service name='persistence' "+ " factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" + "</jbpm-context>"+ // Also all the resource files that are used by jbpm are // referenced from the 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() { // Between the 3 method calls below, all data is passed via the // database. Here, in this unit test, these 3 methods are executed // right after each other because we want to test a complete process // scenario. But in reality, these methods represent different // requests to a server. // Since we start with a clean, empty in-memory database, we have to // deploy the process first. In reality, this is done once by the // process developer. deployProcessDefinition(); // Suppose we want to start a process instance (=process execution) // when a user submits a form in a web application... processInstanceIsCreatedWhenUserSubmitsWebappForm(); // Then, later, upon the arrival of an asynchronous message the // execution must continue. theProcessInstanceContinuesWhenAnAsyncMessageIsReceived(); } public void deployProcessDefinition() { // This test shows a process definition and one execution // of the process definition. The process definition has // 3 nodes: an unnamed start-state, a state 's' and an // end-state named '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>" ); //Lookup the pojo persistence context-builder that is configured above JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // Deploy the process definition in the database jbpmContext.deployProcessDefinition(processDefinition); } finally { // Tear down the pojo persistence context. // This includes flush the SQL for inserting the process definition // to the database. jbpmContext.close(); } } public void processInstanceIsCreatedWhenUserSubmitsWebappForm() { // The code in this method could be inside a struts-action // or a JSF managed bean. //Lookup the pojo persistence context-builder that is configured above JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); //With the processDefinition that we retrieved from the database, we //can create an execution of the process definition just like in the //hello world example (which was without persistence). ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); assertEquals("start", token.getNode().getName()); // Let's start the process execution token.signal(); // Now the process is in the state 's'. assertEquals("s", token.getNode().getName()); // Now the processInstance is saved in the database. So the // current state of the execution of the process is stored in the // database. jbpmContext.save(processInstance); // The method below will get the process instance back out // of the database and resume execution by providing another // external signal. } finally { // Tear down the pojo persistence context. jbpmContext.close(); } } public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() { //The code in this method could be the content of a message driven bean. // Lookup the pojo persistence context-builder that is configured above JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); // First, we need to get the process instance back out of the // database. There are several options to know what process // instance we are dealing with here. The easiest in this simple // test case is just to look for the full list of process instances. // That should give us only one result. So let's look up the // process definition. ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); //Now search for all process instances of this process definition. List processInstances = graphSession.findProcessInstances(processDefinition.getId()); // Because we know that in the context of this unit test, there is // only one execution. In real life, the processInstanceId can be // extracted from the content of the message that arrived or from // the user making a choice. ProcessInstance processInstance = (ProcessInstance) processInstances.get(0); // Now we can continue the execution. Note that the processInstance // delegates signals to the main path of execution (=the root token). processInstance.signal(); // After this signal, we know the process execution should have // arrived in the end-state. assertTrue(processInstance.hasEnded()); // Now we can update the state of the execution in the database jbpmContext.save(processInstance); } finally { // Tear down the pojo persistence context. jbpmContext.close(); } } }
public class HelloWorldDbTest extends TestCase {
static JbpmConfiguration jbpmConfiguration = null;
static {
// An example configuration file such as this can be found in
// 'src/config.files'. Typically the configuration information
// is in the resource file 'jbpm.cfg.xml', but here we pass in
// the configuration information as an XML string.
// First we create a JbpmConfiguration statically. One
// JbpmConfiguration can be used for all threads in the system,
// that is why we can safely make it static.
jbpmConfiguration = JbpmConfiguration.parseXmlString(
"<jbpm-configuration>" +
// A jbpm-context mechanism separates the jbpm core
// engine from the services that jbpm uses from
// the environment.
"<jbpm-context>"+
"<service name='persistence' "+
" factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" +
"</jbpm-context>"+
// Also all the resource files that are used by jbpm are
// referenced from the 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() {
// Between the 3 method calls below, all data is passed via the
// database. Here, in this unit test, these 3 methods are executed
// right after each other because we want to test a complete process
// scenario. But in reality, these methods represent different
// requests to a server.
// Since we start with a clean, empty in-memory database, we have to
// deploy the process first. In reality, this is done once by the
// process developer.
deployProcessDefinition();
// Suppose we want to start a process instance (=process execution)
// when a user submits a form in a web application...
processInstanceIsCreatedWhenUserSubmitsWebappForm();
// Then, later, upon the arrival of an asynchronous message the
// execution must continue.
theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
}
public void deployProcessDefinition() {
// This test shows a process definition and one execution
// of the process definition. The process definition has
// 3 nodes: an unnamed start-state, a state 's' and an
// end-state named '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>"
);
//Lookup the pojo persistence context-builder that is configured above
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
// Deploy the process definition in the database
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
// Tear down the pojo persistence context.
// This includes flush the SQL for inserting the process definition
// to the database.
jbpmContext.close();
}
}
public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {
// The code in this method could be inside a struts-action
// or a JSF managed bean.
//Lookup the pojo persistence context-builder that is configured above
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
GraphSession graphSession = jbpmContext.getGraphSession();
ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition("hello world");
//With the processDefinition that we retrieved from the database, we
//can create an execution of the process definition just like in the
//hello world example (which was without persistence).
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
assertEquals("start", token.getNode().getName());
// Let's start the process execution
token.signal();
// Now the process is in the state 's'.
assertEquals("s", token.getNode().getName());
// Now the processInstance is saved in the database. So the
// current state of the execution of the process is stored in the
// database.
jbpmContext.save(processInstance);
// The method below will get the process instance back out
// of the database and resume execution by providing another
// external signal.
} finally {
// Tear down the pojo persistence context.
jbpmContext.close();
}
}
public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {
//The code in this method could be the content of a message driven bean.
// Lookup the pojo persistence context-builder that is configured above
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
GraphSession graphSession = jbpmContext.getGraphSession();
// First, we need to get the process instance back out of the
// database. There are several options to know what process
// instance we are dealing with here. The easiest in this simple
// test case is just to look for the full list of process instances.
// That should give us only one result. So let's look up the
// process definition.
ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition("hello world");
//Now search for all process instances of this process definition.
List processInstances =
graphSession.findProcessInstances(processDefinition.getId());
// Because we know that in the context of this unit test, there is
// only one execution. In real life, the processInstanceId can be
// extracted from the content of the message that arrived or from
// the user making a choice.
ProcessInstance processInstance =
(ProcessInstance) processInstances.get(0);
// Now we can continue the execution. Note that the processInstance
// delegates signals to the main path of execution (=the root token).
processInstance.signal();
// After this signal, we know the process execution should have
// arrived in the end-state.
assertTrue(processInstance.hasEnded());
// Now we can update the state of the execution in the database
jbpmContext.save(processInstance);
} finally {
// Tear down the pojo persistence context.
jbpmContext.close();
}
}
}
2.3. 上下文示例:进程变量 复制链接链接已复制到粘贴板!
复制链接链接已复制到粘贴板!
执行 whilst 进程,上下文信息保存在 进程变量 中。它们类似于
java.util.Map
类,其中将变量名称映射到值,后者是 Java 对象。(进程变量是"持久性",作为进程实例的一部分。)
注意
为了保持以下示例简单,仅显示使用变量所需的应用程序编程接口(没有任何持久性功能)。
注意
通过阅读来了解更多有关变量的信息 第 7 章 上下文
// This example also starts from the hello world process. // This time even without modification. 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); // Fetch the context instance from the process instance // for working with the process variables. ContextInstance contextInstance = processInstance.getContextInstance(); // Before the process has left the start-state, // we are going to set some process variables in the // context of the process instance. contextInstance.setVariable("amount", new Integer(500)); contextInstance.setVariable("reason", "i met my deadline"); // From now on, these variables are associated with the // process instance. The process variables are now accessible // by user code via the API shown here, but also in the actions // and node implementations. The process variables are also // stored into the database as a part of the process instance. processInstance.signal(); // The variables are accessible via the contextInstance. assertEquals(new Integer(500), contextInstance.getVariable("amount")); assertEquals("i met my deadline", contextInstance.getVariable("reason"));
// This example also starts from the hello world process.
// This time even without modification.
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);
// Fetch the context instance from the process instance
// for working with the process variables.
ContextInstance contextInstance =
processInstance.getContextInstance();
// Before the process has left the start-state,
// we are going to set some process variables in the
// context of the process instance.
contextInstance.setVariable("amount", new Integer(500));
contextInstance.setVariable("reason", "i met my deadline");
// From now on, these variables are associated with the
// process instance. The process variables are now accessible
// by user code via the API shown here, but also in the actions
// and node implementations. The process variables are also
// stored into the database as a part of the process instance.
processInstance.signal();
// The variables are accessible via the contextInstance.
assertEquals(new Integer(500),
contextInstance.getVariable("amount"));
assertEquals("i met my deadline",
contextInstance.getVariable("reason"));
2.4. 任务分配示例 复制链接链接已复制到粘贴板!
复制链接链接已复制到粘贴板!
下一示例演示了如何为用户分配任务。由于 jBPM 工作流引擎和组织模型之间的隔离,表达式语言将始终仅限于使用计算参与者。相反,指定
AssignmentHandler
实施,并使用它来包含任务执行者的计算。
public void testTaskAssignment() { // The process shown below is based on the hello world process. // The state node is replaced by a task-node. The task-node // is a node in JPDL that represents a wait state and generates // task(s) to be completed before the process can continue to // execute. 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>" ); // Create an execution of the process definition. ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); // Let's start the process execution, leaving the start-state // over its default transition. token.signal(); // The signal method will block until the process execution // enters a wait state. In this case, that is the task-node. assertSame(processDefinition.getNode("t"), token.getNode()); // When execution arrived in the task-node, a task 'change nappy' // was created and the NappyAssignmentHandler was called to determine // to whom the task should be assigned. The NappyAssignmentHandler // returned 'papa'. // In a real environment, the tasks would be fetched from the // database with the methods in the org.jbpm.db.TaskMgmtSession. // Since we don't want to include the persistence complexity in // this example, we just take the first task-instance of this // process instance (we know there is only one in this test // scenario). TaskInstance taskInstance = (TaskInstance) processInstance .getTaskMgmtInstance() .getTaskInstances() .iterator().next(); // Now, we check if the taskInstance was actually assigned to 'papa'. assertEquals("papa", taskInstance.getActorId() ); // Now we suppose that 'papa' has done his duties and mark the task // as done. taskInstance.end(); // Since this was the last (only) task to do, the completion of this // task triggered the continuation of the process instance execution. assertSame(processDefinition.getNode("end"), token.getNode()); }
public void testTaskAssignment() {
// The process shown below is based on the hello world process.
// The state node is replaced by a task-node. The task-node
// is a node in JPDL that represents a wait state and generates
// task(s) to be completed before the process can continue to
// execute.
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>"
);
// Create an execution of the process definition.
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
// Let's start the process execution, leaving the start-state
// over its default transition.
token.signal();
// The signal method will block until the process execution
// enters a wait state. In this case, that is the task-node.
assertSame(processDefinition.getNode("t"), token.getNode());
// When execution arrived in the task-node, a task 'change nappy'
// was created and the NappyAssignmentHandler was called to determine
// to whom the task should be assigned. The NappyAssignmentHandler
// returned 'papa'.
// In a real environment, the tasks would be fetched from the
// database with the methods in the org.jbpm.db.TaskMgmtSession.
// Since we don't want to include the persistence complexity in
// this example, we just take the first task-instance of this
// process instance (we know there is only one in this test
// scenario).
TaskInstance taskInstance = (TaskInstance)
processInstance
.getTaskMgmtInstance()
.getTaskInstances()
.iterator().next();
// Now, we check if the taskInstance was actually assigned to 'papa'.
assertEquals("papa", taskInstance.getActorId() );
// Now we suppose that 'papa' has done his duties and mark the task
// as done.
taskInstance.end();
// Since this was the last (only) task to do, the completion of this
// task triggered the continuation of the process instance execution.
assertSame(processDefinition.getNode("end"), token.getNode());
}
2.5. 自定义操作示例 复制链接链接已复制到粘贴板!
复制链接链接已复制到粘贴板!
操作 是一种机制,用于将自定义 Java 代码绑定到 IaaS 进程。它们可以与自己的节点关联(如果它们与进程的图形表示相关)。 或者,也可以"替换"事件(例如,在进行转换时、进入或离开节点时)操作。 如果将它们放在事件中,则操作不会被视为图形表示的一部分(但在事件在执行期间仍然在运行它们。)
首先,查看下例中使用的操作处理程序实施:
MyActionHandler
。它本身并不是特别注意的:它只是设置布尔值变量 被执行为
true
。请注意,此变量是静态的,因此可以从操作处理程序内(以及操作本身)访问它以验证其值。
注意
有关"actions"的更多信息,请参阅 第 6.5 节 “Actions”
// MyActionHandler represents a class that could execute // some user code during the execution of a jBPM process. public class MyActionHandler implements ActionHandler { // Before each test (in the setUp), the isExecuted member // will be set to false. public static boolean isExecuted = false; // The action will set the isExecuted to true so the // unit test will be able to show when the action // is being executed. public void execute(ExecutionContext executionContext) { isExecuted = true; } }
// MyActionHandler represents a class that could execute
// some user code during the execution of a jBPM process.
public class MyActionHandler implements ActionHandler {
// Before each test (in the setUp), the isExecuted member
// will be set to false.
public static boolean isExecuted = false;
// The action will set the isExecuted to true so the
// unit test will be able to show when the action
// is being executed.
public void execute(ExecutionContext executionContext) {
isExecuted = true;
}
}
重要
在每个测试前,将静态字段
MyActionHandler.isExecuted
设置为 false
。
// Each test will start with setting the static isExecuted // member of MyActionHandler to false. public void setUp() { MyActionHandler.isExecuted = false; }
// Each test will start with setting the static isExecuted
// member of MyActionHandler to false.
public void setUp() {
MyActionHandler.isExecuted = false;
}
第一个示例演示了一个转换的操作:
public void testTransitionAction() { // The next process is a variant of the hello world process. // We have added an action on the transition from state 's' // to the end-state. The purpose of this test is to show // how easy it is to integrate Java code in a jBPM process. 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>" ); // Let's start a new execution for the process definition. ProcessInstance processInstance = new ProcessInstance(processDefinition); // The next signal will cause the execution to leave the start // state and enter the state 's' processInstance.signal(); // Here we show that MyActionHandler was not yet executed. assertFalse(MyActionHandler.isExecuted); // ... and that the main path of execution is positioned in // the state 's' assertSame(processDefinition.getNode("s"), processInstance.getRootToken().getNode()); // The next signal will trigger the execution of the root // token. The token will take the transition with the // action and the action will be executed during the // call to the signal method. processInstance.signal(); // Here we can see that MyActionHandler was executed during // the call to the signal method. assertTrue(MyActionHandler.isExecuted); }
public void testTransitionAction() {
// The next process is a variant of the hello world process.
// We have added an action on the transition from state 's'
// to the end-state. The purpose of this test is to show
// how easy it is to integrate Java code in a jBPM process.
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>"
);
// Let's start a new execution for the process definition.
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
// The next signal will cause the execution to leave the start
// state and enter the state 's'
processInstance.signal();
// Here we show that MyActionHandler was not yet executed.
assertFalse(MyActionHandler.isExecuted);
// ... and that the main path of execution is positioned in
// the state 's'
assertSame(processDefinition.getNode("s"),
processInstance.getRootToken().getNode());
// The next signal will trigger the execution of the root
// token. The token will take the transition with the
// action and the action will be executed during the
// call to the signal method.
processInstance.signal();
// Here we can see that MyActionHandler was executed during
// the call to the signal method.
assertTrue(MyActionHandler.isExecuted);
}
下一示例显示,现在将相同的操作放在
enter-node
和 leave-node
事件上。请注意,节点有多个事件类型。这与一个 转换 不同,它只有一个事件。因此,当将操作放在某个节点上时,始终将它们放在 event 元素中。
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); // The next signal will cause the execution to leave the start // state and enter the state 's'. So the state 's' is entered // and hence the action is executed. processInstance.signal(); assertTrue(MyActionHandler.isExecuted); // Let's reset the MyActionHandler.isExecuted MyActionHandler.isExecuted = false; // The next signal will trigger execution to leave the // state 's'. So the action will be executed again. processInstance.signal(); // Voila. assertTrue(MyActionHandler.isExecuted);
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);
// The next signal will cause the execution to leave the start
// state and enter the state 's'. So the state 's' is entered
// and hence the action is executed.
processInstance.signal();
assertTrue(MyActionHandler.isExecuted);
// Let's reset the MyActionHandler.isExecuted
MyActionHandler.isExecuted = false;
// The next signal will trigger execution to leave the
// state 's'. So the action will be executed again.
processInstance.signal();
// Voila.
assertTrue(MyActionHandler.isExecuted);