Chapter 3. Tutorial指南
This tutorial will show you basic process constructs 过程建造in jpdl and the usage of the API for managing the runtime executions.
这本指南将告诉你使用jpdl语言构建基本的工作流程,以及管理运行时执行的API的用法。
The format of this tutorial is explaining a set of examples. The examples focus on a particular topic and contain extensive comments. The examples can also be fond in the jBPM download package in the directory src/java.examples.
这篇指南解释一系列的例子。例子聚焦于一个特殊的主题和包含很多的注释。
The best way to learn is to create a project and experiment by creating variations on the examples given.
最好的学习方式是在例子的基础上创建一个略为不同的项目。
To get started for eclipse users: download jbpm-3.0-[version].zip and unzip it to your sytem. Then do "File" --> "Import..." --> "Existing Project into Workspace". Click "Next" Then, browse for the jBPM root directory and click "Finish". Now you have a jbpm.3 project in your workspace. You can now find the examples of the tutorial in src/java.examples/.... When you open these examples, you can run them with "Run" --> "Run As..." --> "JUnit Test"
用Junit运行自带的例子。
jBPM includes a graphical designer tool for authoring 创作the XML that is shown in the examples. You can find download instructions指令 for the graphical designer in Section 2.1, “Downloadables Overview”. You don't need the graphical designer tool to complete this tutorial.
State machines can be
你不需要图形设计器就能完成这篇指南。图形设计器仅仅帮助你制作xml流程定义文件。
A process definition is a directed graph, made up of nodes and transitions. The hello world process has 3 nodes. To see how the pieces fit together, we're going to start with a simple process without the use of the designer tool. The following picture shows the graphical representation of the hello world process:
一个过程定义是一个直接的图表,由“节点”和“转向”组成。Hello world这个例子的过程定义有3个节点。
下面的图像显示了hello world过程定义的图形化表示。

Figure 3.1. The hello world process graph
Hello world业务处理图表
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.
/*
* 下一行把一段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>"
);
// 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.
/**
*下一行使用 代表过程定义的Model对象--ProcessDefinition实例,创建一个业务处理定义的执行
* 构造之后,在开始状态/节点,业务处理执行对象有一个主要的执行路径
*
*/
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
// After construction, the process execution has one main path
// of execution (=the root token).
/*记号,得到主要的执行路径。
* 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();用来执行一步状态,利用“转向”跳到下一步状态。
*
* */
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 not
// 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.
/*
* 让我们发送另一个信号。这将执行离开状态s的转向。
* */
token.signal();
// Now the signal method returned because the process instance
// has arrived in the end-state.
assertSame(processDefinition.getNode("end"), token.getNode());
}
参考:
1,记号类,代表一个工作处理定义的一条工作流程。
public class Token
extends java.lang.Object
implements java.io.Serializable
represents one path of execution and maintains a pointer to a node in the ProcessDefinition. Most common way to get a hold of the token objects is with ProcessInstance.getRootToken() or ProcessInstance.findToken(String).
这个类代表了一个过程的执行流程。使用
public void signal()
provides a signal to the token. this method activates this token and leaves the current state over the default transition.
方法执行一步。
2,工作处理实例 类
public class ProcessInstance
extends java.lang.Object
implements java.io.Serializable
is one execution of a ProcessDefinition. To create a new process execution of a process definition, just use the ProcessInstance(ProcessDefinition).
这个类根据作为Model数据容器类的ProcessDefinition工作处理定义类的一个实例创建。代表一个工作处理定义的执行。主要关注于工作处理相关的操作。
public Token getRootToken() 得到工作处理定义的从start状态开始的一条记号----工作流程。
public Token findToken(java.lang.String tokenPath)looks up the token in the tree, specified by the slash-separated token path.
Parameters:
tokenPath - is a slash-separated name that specifies a token in the tree.
Returns:
the specified token or null if the token is not found.
在工作处理定义的树中,根据记号路径/工作流程路径得到一条工作流程
。
数据库例子
One of the basic features of jBPM is the ability to persist executions of processes in the database when they are in a wait state. The next example will show you how to store a process instance in the jBPM database. The example also suggests a context in which this might occur. Separate methods are created for different pieces of user code. E.g. an piece of user code in a web application starts a process and persists the execution in the database. Later, a message driven bean loads the process instance from the database and resumes its execution.
jBPM的一个基本的特性是,它能够在业务处理处于等待状态时,把业务处理的执行结果储存到数据库中。下一个例子讲告诉你怎样把一个业务处理的实例保存进jBPM数据库。例子也展示了可能发生这种情况的场景。如,用户的业务处理代码由几个独立的方法组成,例如,一部分用户代码是,在一个Web应用程序中开始一个处理,并且把这个处理保存进数据库。然后,一个消息驱动的bean从数据库中引导这个业务处理实例----也就是业务处理定义的一个执行的实例(注意: ProcessDefinition业务处理定义是一个Model,保存xml格式的业务处理图表,一种DSL特定领域语言;而ProcessInstance业务处理实例,也是一个Model,它是保存业务处理定义的一次执行的信息。具体的操作由从它得到的Token记号类执行。Token类是Action类,真正执行业务处理的流程。Token类应该叫做“工作流程类”,代表了业务处理的一条工作流程),恢复它的执行。
这样,jBPM的业务处理具有分段、异步执行的能力。
More about the jBPM persistence can be found in Chapter 7, Persistence.
API参考:
1,Jbpm配置
public class JbpmConfiguration
extends java.lang.Object
implements java.io.Serializable
configuration of one jBPM instance.一个jBPM实例的配置。也就是说,jBPM可以使用多个jBPM配置。基本上,一个jBPM的业务处理可以使用一个JbpmConfiguration对象的实例。
During process execution, jBPM might need to use some services. A JbpmConfiguration contains the knowledge on how to create those services.
在业务处理的执行过程中,jBPM可能需要使用一些服务。一个Jbpm配置类包含了怎样创建这些服务的知识。
A JbpmConfiguration is a thread safe object and serves as a factory for JbpmContexts, which means one JbpmConfiguration can be used to create JbpmContexts for all threads. The single JbpmConfiguration can be maintained in a static member or in the JNDI tree if that is available.
一个JbpmConfiguration能够被用来为所有的线程创建JbpmContext。JbpmConfiguration.createJbpmContext();方法创建Jbpm上下文环境类的一个实例。
JbpmConfiguration应该使用单例,如静态成员,或者JNDI树,或者IOC容器管理的单例等。
A JbpmConfiguration can be obtained in following ways:
· JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
or
String myXmlResource = "...";
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(myXmlResource);
· JbpmConfiguration jbpmConfiguration = JbpmConfiguration.parseXmlString(
· "" +
· ...
· ""
· );
通过指定一个对象工厂的定制实现。被用在JBoss或者Spring容器中。
· ObjectFactory of = new MyCustomObjectFactory();
· JbpmConfiguration.Configs.setDefaultObjectFactory(of);
· JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmConfigurations can be configured using a spring-like XML notation (in relax ng compact notation):
datatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes"
start = element beans { element object* }
object = {
jbpm-context |
bean |
ref |
map |
list |
string |
int |
long |
float |
double |
char |
bool |
true |
false |
null
}
jbpm-context = element jbpm-context {
( attribute name {xsd:string},
service*,
save-operations?
)
}
service = element service {
( attribute name {xsd:string},
( attribute factory {xsd:string} ) |
( factory )
)
}
factory = element factory {
( bean |
ref
)
}
save-operations = element save-operations {
( save-operation* )
}
save-operation = element save-operation {
( ( attribute class {xsd:string} ) |
( bean |
ref
)
)
}
bean = element bean {
( attribute ref-name {xsd:string} ) |
( attribute name {xsd:string}?,
attribute class {xsd:string}?,
attribute singleton { "true" | "false" }?,
constructor*,
field*,
property*
)
}
ref = element ref {
( attribute bean (xsd:string) )
}
constructor = element constructor {
attribute class {xsd:string}?,
( attribute factory {xsd:string},
attribute method {xsd:string}
)?,
parameter*
}
parameter = element parameter {
attribute class {xsd:string},
object
}
field = element field {
attribute name {xsd:string},
object
}
property = element property {
( attribute name {xsd:string} |
attribute setter {xsd:string}
),
object
}
map = element map {
entry*
}
entry = element entry {
key,
value
}
key = element key {
object
}
value = element value {
object
}
list = element list {
object*
}
string = element string {xsd:string}
int = element integer {xsd:integer}
long = element long {xsd:long}
float = element float {xsd:string}
double = element string {xsd:double}
char = element char {xsd:character}
bool = element bool { "true" | "false" }
true = element true {}
false = element false {}
null = element null {}
Other configuration properties
| jbpm.msg.wait.timout | |
| jbpm.files.dir | |
| jbpm.types | |
2,Jbpm上下文环境
public class JbpmContext
extends java.lang.Object
implements java.io.Serializable
is used to surround persistent operations to processes.
被用来负责业务处理的持久化操作。它底层使用Hibernate等数据库持久化技术来与数据库中的保存业务处理图表、业务处理的执行等的数据库表交互。
Obtain JbpmContext's via JbpmConfiguration.createJbpmContext() and put it in a try-finally block like this:
作为一个数据库持久化资源,必须要关闭。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
TaskInstance taskInstance = ...
...do your process operations...
// in case you update a process object that was not fetched
// with a ...ForUpdate method, you have to save it.
/*
*/
jbpmContext.save(processInstance);
finally {
jbpmContext.close();
}
A JbpmContext separates jBPM from a sprecific environment. For each service that jBPM uses, there is an interface specified in the jBPM codebase. jBPM also includes implementations that implement these services by using services in a specific environment. e.g. a hibernate session, a JMS asynchronous messaging system, ...
JbpmContext从一个jBPM实例的环境中分离而来。每一个jBPM使用的服务,在jBPM的代码库中有指定的借口。jBPM也包括在一个特定环境中使用这些服务的实现类。
A JbpmContext can demarcate a transaction. When a PersistenceService is fetched from the JbpmContext, the default implementation for the persistence service will create a hibernate session and start a transaction. So that transactions can be configured in the hibernate configuration.
JbpmContext能够使用事务。如果一个持久化服务是从JbpmContext中来的,那么默认的持久化实现是Hibernate,那么将会创建一个Hibernate会话和事务。
A JbpmContext allows the user to overwrite重写 (or make complete) the configuration by injecting objects programmatically编程注入对象. like e.g. a hibernate session factory or a hibernate session or any other resource that can be fetched or created from the configuration.
Last but not least, JbpmContext provides convenient方便的 access to the most common operations such as getTaskList(String), newProcessInstance(String) loadTaskInstanceForUpdate(long) and save(ProcessInstance).
All the ...ForUpdate(...) methods will automatically save the loaded objects at jbpmContext.close();
所有这些涉及到数据库更新的操作,都会在jbpmContext.close()调用时被自动保存到数据库中。
3,GraphSession类 业务处理图表会话类,更确切的名字:业务处理定义 会话类
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc.,
* 02110-1301
*/
package org.jbpm.tutorial.db;
import java.util.List;
import junit.framework.TestCase;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.GraphSession;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
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能够被系统中所有线程所使用。
*jbpm.cfg.xml这个命名方式和Hibernate配置文件的命名方式一致。
*
*/
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机制在环境中把jbpm核心引擎和jbpm使用的服务分开。
* 持久化服务是jbpm核心引擎使用的一个服务。
*
* */
" <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,配置了所有jbpm使用的资源文件的路径。
* */
" <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.
/**
* 这个方法把业务处理定义通过Hibernate保存到数据库中。
*/
deployProcessDefinition();