JBPM布署及入门

1.     jBPM的简单介绍
jBPM 是JBOSS下的一个开源java工作流项目,该项目提供eclipse插件,基于Hibernate实现数据持久化存储。
   参考
2.     jBPM和myeclipse的冲突
当eclipse安装了myeclipse和jBPM时候,可能有冲突,具体表现在jBPM的流程设计器不能在eclipse中使用。
 
3.     Hibernate连接mysql数据库的一般参数
下面的配置参数,根据需要可以修改:
jbpmtest 是mysql中的schema的名字;
GBK 是字符集,可以根据需要修改;
username=root ,mysql数据库的用户名是root
password=mysql ,mysql数据库的用户密码是mysql
 
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url= jdbc : mysql://localhost/jbpmtest?useUnicode=true&characterEncoding=GBK
hibernate.connection.username = root
hibernate.connection.password = mysql
 
hibernate.show_sql = true
hibernate.c3p0.min_size= 1
hibernate.c3p0.max_size= 3
 
4.     Hibernate连接Oracle数据库的一般参数
hibernate.dialect = org.hibernate.dialect.Oracle9Dialect
hibernate.connection.driver_class= oracle.jdbc.driver.OracleDriver
hibernate.connection.url = jdbc:oracle:thin:@ localhost :1521:orclhibernate.connection.username= jbpm
hibernate.connection.password = jbpm
 
5.     为jBPM创建数据库表等内容
5.1.            为mysql创建数据库以及数据内容
JbpmSessionFactory.buildJbpmSessionFactory (). getJbpmSchema().dropSchema();
JbpmSessionFactory.buildJbpmSessionFactory (). getJbpmSchema().createSchema();
这2个语针对mysq有效.
5.2.            为oralce创建数据库以及数据内容
JbpmSessionFactory.buildJbpmSessionFactory (). getJbpmSchema().dropSchema();
JbpmSessionFactory.buildJbpmSessionFactory (). getJbpmSchema().createSchema();
上面的语句对 oralce无效。
模型目录jBPM/jbpm_database/jBPM_oralce10g.pdm 是 jBPM的 Oralce模型,包含对应的Sequence的信息.
需要在数据库中创建 Sequence name= hibernate_sequence
5.3.            流程信息保存到数据库
JbpmSessionFactory  factory =   JbpmSessionFactory.buildJbpmSessionFactory();
        JbpmSession session = factory.openJbpmSession();
        GraphSession graphSession =  session.getGraphSession();
        session.beginTransaction();
        
        /// new ProcessDefinition 实例
        ProcessDefinition myProcessDefinition = null;
    ProcessInstance processInstance = newProcessInstance(processDefinition);
      processInstance.getContextInstance().setVariable("myvar","xxx");
        ///
        graphSession.saveProcessDefinition(myProcessDefinition);
        session.commitTransaction();
session.close ();
jBPM和 Hibernate,MySQL的使用中会遇到字符集的问题.
需要注意几个地方。
5.4.            在Mysql安装过程指定字符集
   在 Mysql安装过程中指定相应的默认字符集是GBK
5.5.            Hibernate.properties文件中的字符集设置
hibernate.connection.url=jdbc:mysql://localhost/jbpmtest?useUnicode=true&characterEncoding=GBK
5.6.            hibernate.cfg.xml 文件中的字符集设置
< property name="hibernate.connection.url">jdbc:mysql://192.168.1.2/jbpmtest</property>
5.7.            MySQL的配置文件的修改:
   my.ini中 default-character-set=GBK
   注意有2处需要修改
 
6.     为流程定义变量
分成3种流程变量
全局变量(全局流程变量)
全局临时变量(全局流程临时变量)
局部变量(流程某个接点内有效的变量)
@see org.jbpm.context.exe.ContextInstance
目前还没有使用过局部变量(流程某个接点内有效的变量)
流程变量的定义
6.1.            流程变量的类型
·         java.lang.String
·         java.lang.Boolean
·         java.lang.Character
·         java.lang.Float
·         java.lang.Double
·         java.lang.Long
·         java.lang.Byte
·         java.lang.Short
·         java.lang.Integer
·         java.util.Date
·         byte[]
·         java.io.Serializable
·         classes that are persistable with hibernate
 所有基本类型的包裹类型,以及实现了 Serializable 的类型都可以作为流程参数变量使用,注意参数类不能是一个类的内部类或者属性类(除非包含参数类的类实现了Serializable接口)
参考 org.jbpm.context.exe.VariableInstance
6.2.            流程变量的使用
l        变量的定义和获取
void ContextInstance.setVariable(String variableName, Object value);
void ContextInstance.setVariable(String variableName, Object value, Token token);
ObjectContextInstance.getVariable(String variableName);
ObjectContextInstance.getVariable(String variableName, Token token);
l        Variables can be deleted with
ContextInstance.deleteVariable ( String variableName);
ContextInstance.deleteVariable ( String variableName, Token token);
 
6.3.            Variable lifetime
    一个变量在被定义后,在变量从 ContextInstance 删除前,都可以被访问。当变量被删除后,去获取该变量将返回为空。
6.4.            自定义类的实例作为流程变量
   如果一个类的实例要作为流程变量使用,该类需要实现 java.io.Serializable 接口,并且定义序列化版本.
 
//一个可以作为流程变量使用的类
class Wdz implements Serializable{
    //为类指定序列化版本号
    private static final long serialVersionUID = 1L;    
       private String name="wdz";
       private int age=10;
       public String toString(){
              return "name="+name+",age="+age;    
       }    
}
上面的例子中,如果把类 Wdz作为类 WdzParent内部类使用,然后当成流程变量使用,那类 WdzParent必须 也实现 Serializable接口,否则会有问题.
6.5.            Transient variables
流程的历史变量是不能持久化的,作用范围是对整个流程全局有效的。
在 ContextInstance类内部,采用的是一个Map来存储 TransientVariable的信息
参考代码
org.jbpm.context.exe.ContextInstance 的源代码。
主要的相关方法
public voiddeleteTransientVariable(java.lang.String name)
public voidsetTransientVariable(java.lang.String name,
                                 java.lang.Object value)
public java.lang.Object getTransientVariable( java.lang.String  name)
 
6.6.            Variables overloading
 当一个变量和流实例关联(变量名字= ”wdz”,value=”test”),如果在设置一个变量
(变量名字= ”wdz”,value= new Integer(10)) ,那最后变量(变量名字= ”wdz)的值是Integer(10)。
这称之为overload.
 
6.7.            Variables overriding
 如果父流程有变量A(值= ”value1”),子流程又定义了变量A值= ”value2”,那在子流程范围内,获取变量A的值,那结果是值= ”value2”。这是遵循一般语言的局部变量在它的局部范围内override上级变量。
 
6.8.            流程变量的持久化
它依赖于流程实例的持久化,非 TransientVariable流程实例的持久化一起被保存。
保存在数据表 jbpm_variableinstance
参考 org.jbpm.context.exe.VariableInstance
6.9.            Customizing variable persistence (可以进一步了解)
User java object <---> converter <--->  variable instance
也就是自定义类的持久化需要定义自己的 converter 和变量实例类
converter 和变量实例类需要继承 org.jbpm.context.exe.VariableInstance
converter 需要实现 org.jbpm.context.exe.Converter 接口

 

工作流虽然还在不成熟的发展阶段,甚至还没有一个公认的规范标准。但其应用却已经在快速展开,这说明市场对工作流框架的需求是急迫而巨大的。

    我们公司的后台短信管理系统涉及短信编发、领导层层审核等操作,这是一个比较典型的工作流系统。过去我们用的工作流引擎是 shark,然后在使用后发现其过于庞大,后台数据库操作频繁而未进行优化,直接导致的后果就是前台操作缓慢。于是经研究决定,将工作流引擎由 shark换成 jBPM

    jBPM之前是一个开源软件,后加入 JBoss组织。正好我们公司也是用 JBoss的。不过 jBPM 并没有绑定在 JBOSS 上, Tomcat 等也可以使用它。

    jBPM的正处在不断发展中,做为开源软件的特点,其设计变化往往很大。所以一些过去的资料可能已经不适用了。于是作者根据自己的使用经验,重新整理出这份文档,以备学习参考。

注:本文使用的 jBPM版本为 3.1.1

环境准备

1、安装JDK

所有 JAVA开发第一个需要安装的,没什么好说的。记得把系统变量 JAVA_HOME设上。

2、安装Ant

Ant 是使用 jBPM必须的一个工具。 jBPM中的很多操作都要用到 Ant

安装方法:

1)先下载:http://archive.apache.org/dist/ant/binaries/,选一个如: apache-ant-1.6.5-bin.zip

2)解压到 D:/ant(当然其他目录也可以)。

3)设置如下系统变量: ANT_HOME=d:/ant

4)把 %ANT_HOME%/bin加入到系统变量 PATH中。

3、安装Eclipse

Eclipse不是开发 jBPM必须的工具,但它是对 jBPM开发很有帮助的工具,特别是 jBPM提供了一个 Eclipse插件用来辅助开发 jBPM 。关于 Eclipse 的安装不赘述了,本文用的版本是: Eclipse3.2

 

安装 jBPM

jBPM 的下载地址:http://nchc.dl.sourceforge.net/sourceforge/jbpm/jbpm-starters-kit-3.1.2.zip

l          JBoss jBPM jBPM的软件包

l          JBoss jBPM Starters Kit 是一个综合包,它包括了 jBPM软件包、开发插件、一个配置好了的基于 JBoss jBPM示例、一些数据库配置文件示例。

l          JBoss jBPM Process Designer Plugin 是辅助开发 jBPM Eclipse插件。

l          JBoss jBPM BPEL Extension jBPM关于 BPEL的扩展包

本指南选择下载: JBoss jBPM Starters Kit。下载后解压到 D:/jbpm-starters-kit-3.1,目录下含有五个子目录:

l          jbpm  jBPM的软件包

l          jbpm-bpel只含有一个网页

l          jbpm-db各种数据库 hibernate配置文件示例,有些还包含了相应的 jdbc驱动程序。

l          jbpm-designer 辅助开发 jBPM Eclipse插件,具体在 jbpm-gpd-feature子目录中

l          jbpm-server 一个已经配置好了的基于 JBoss jBPM示例 .

 

感觉下工作流

前面我们说了,在 JBoss jBPM Starters Kit jbpm-server目录是一个已经配置好的了 jBPM示例,那么让我们来感觉一下 jBPM做出的东西吧。

 

双击 jbpm-server目录下的 start.bat文件,启动 JBoss 服务。这时会打开一个 DOS 窗口,启动完成后,日志会不断输出,其中最后一句是“ 13:55:39,937 DEBUG [StaticNotifier] going to wait for (CMD_EXECUTOR, java.lang.Object@1df59bd)”,这表示 jBPM在开始工作了,它不断进行轮询。

打开网页: http://localhost:8080/jbpm/ 得到如下画面

 

这是一个已经用 jBPM开发好的用户定单流程,具有下单、审核、估价等流程。它所用的数据库是一个内置的数据库。

cookie monster用户登录,选择“ create new web sale order”可以创建一个定单。如下图所示,在图左边是填写的定单情况,右边一整个定货流程的示意图,红色框表示流程进行到哪一步了。填写好定单好,选择“ Save and Close Task”,完成定单提交。

 

选择右上角的“ Login as another user”以另外一个用户名 ernie登录。这时可以看到 ernie用户的任务列表中多了一项。

 

点进去后,显示如下画面。这个示例对中文的支持不好,全都显示成了 unicode码了。不管这什么多,反正知道是这么回事就行了。在 comment项填写意见,选 OK按钮,进入到下一步。如果选择 more info needed按钮,则打回给 cookie monster用户修改定单。

 

 

下面的流程,这里就不再赘述了。在这个很标准的工作流示例中,我们基本可以看到 jBPM的应用范围还是比较广的。而且从这个示例,我们是看不出有 jBPM的,也就是说 jBPM 在后台起着作用。

从这个例子,还看不出 jBPM的优势。不过,如果在一个流程不确定,经常需要变动的项目中, jBPM的好处将会显然出来。应用 jBPM后,改变流程只需改变流程描述文件,这将在后面的内容提到。

这是一个已做好的示例,接下来我们将仿造这个实例来开发一个请假流程。
 

4 数据库初始化

jBPM 需要数据库支持, jBPM会把自己的一个初始化数据存储到数据库,同时工作流的数据也是存储到数据库中的。 jBPM使用 Hibernate来做为自己的存储层,因此只要是 Hibernate支持的数据库, jBPM也就支持。

 

本文先以 MySQL为例,然后再以 Oracle为例,来谈谈 jBPM的数据库初始化操作。

 

注:在上面的 JBoss自带的示例中,并没有设置数据库,那是因为 jBPM默认使用的是内存数据库 hsqldb

4.1 MySQL

 

1 、首先安装 MySQL

MySQL的安装比较简单,网上也有很多文章,本文不再赘述。本指南所用 MySQL版本为 MySQL 4.1 for windows)。再找一个 MySQL客户端,目的是方便查看数据库中的数据,本文推荐使用 MySQL网站上免费提供的“ MySQL Query Brower”,当然你用其他的客户端也行,比如 MySQL-Front

 

2 、建库

MySQL中创建一个库,库名: jbpm

 

3 、生成建表的 SQL语句并建表

jbpm-starters-kit-3.1.1下的子目录 jbpm改名为 jbpm.3,否则在执行下面的 ant命令时会报如 jbpm.3目录不存在的错误:

D:/jbpm-starters-kit-3.1.1/jbpm-db/build.xml:361: The following error occurred while executing this line:

D:/jbpm-starters-kit-3.1.1/jbpm-db/build.xml:68: Basedir D:/jbpm-starters-kit-3.1.1/jbpm.3 does not exist

 

DOS窗下,进入 D:/jbpm-starters-kit-3.1.1/jbpm-db目录,执行如下命令:

ant mysql.scripts

 

执行成功后,在 D:/jbpm-starters-kit-3.1.1/jbpm-db/build/mysql/scripts目录里生成了四个 sql文件,它们做什么用的一看名字就知道了。在 MySQL客户端中执行“ mysql.create.sql”脚本,这样将在 jbpm库中创建一个个的数据表。

 

 

4.2 Oracle

先安装好 Oracle服务器。我们公司有现存的 Oracle服务器,也提供给了我一个属于我自己的用户名,一登录就可以任意在我的库之下创建表了。所以这一步就省了,没有的自个先装好吧。

访问 Oracle推荐用“ PLSQL Developer”。不过要连接 Oracle还要在本机上装上 Oracle自己的客户端程序,里面提供了 JDBC包和一些配置。要连接服务器还得配置一下,我一般都是不用 GUI而直接改 tnsnames.ora文件,在我的电脑里此文件的目录地址是: D:/oracle/ora92/network/ADMIN/tnsnames.ora,内容如下 (两面有两个配置了 )

# TNSNAMES.ORA Network Configuration File: E:/oracle/ora92/network/admin/tnsnames.ora

# Generated by Oracle configuration tools.

 

WXXRDB_192.168.3.2 =

 (DESCRIPTION =

   (ADDRESS_LIST =

     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.3.2)(PORT = 1521))

   )

   (CONNECT_DATA =

     (SID = wxxrDB)

     (SERVER = DEDICATED)

   )

 )

 

WXXRDB_192.168.4.2 =

 (DESCRIPTION =

   (ADDRESS_LIST =

     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.4.2)(PORT = 1521))

   )

   (CONNECT_DATA =

     (SID = wxxrDB)

     (SERVER = DEDICATED)

   )

 )

 

前面都是 Oracle的一些知识,不会的 Google一下吧。最后配置好后,用 PLSQL Developer输入你的用户名和密码联接到 Oracle,就算 OK了。

 

参考上面 MySQL的步骤,基本一样:

1       jbpm改名为 jbpm.3 (或者修改jbpm-db目录下的build.properties文件)

2      再执行ant oracle.scripts

3       jbpm-db/build/oracle/scripts目录的 oracle.create.sql脚本,在 Oracle中生成 jBPM的所有表。在“ PLSQL Developer”中可以新建一个 Command Windows窗口然后输入命令: @D:/jbpm-starters-kit-3.1.1/jbpm-db/build/oracle/scripts/oracle.create.sql

(如果报错,就将报错的地方注释掉)

5  安装 jBPM Eclipse开发插件

有个辅助工具开发起来方便一点,只不过现在 jBPM的开发工具插件功能还不算太强,也就一个“项目创建向导”的功能,让你:

1)不用再去配置 classpath 库的引用了

2)直接得到了一个 jBPM 的项目初始结构

其实吧,开发 jBPM也不需要什么插件工具,在熟练了以后,库引用了项目初始结构都可以手工创建。

 

插件不用再去下载了, jbpm-starters-kit-3.1.1包里就有,目录地址如下:D:/jbpm-starters-kit-3.1.1/jbpm-designer/jbpm-gpd-feature/eclipse,插件的安装方式是链接式还是直接复制式,任选吧。不懂的就去看看《 Eclipse从入门精通》这本书,在前面章节都有讲到。另外,注明一下 Eclipse的版本我是用 3.2,插件和 Eclispe版本相关的,要注意了。

 

如果安装成功,则 Eclipse首选项里多了一个 JBoss jBPM,另外我们也需要到这个 jBPM的首选项里做一些配置工作――指定 jBPM的安装路径(如下图所示)。这个配置主要是为了找到 jbpm下的各种 jar包,好让 Eclipse设置项目的库引用。本文指向路径是 d:/jbpm-starters-kit-3.1.1/jbpm.3

 

6   jBPM Hello World

6.1 新建jBPM项目

主菜单“文件->新建->项目”,在弹出的对话框里,有“ Process Project”项,如下图所示:


选上好,单击“下一步”,起个名“ myjbpm”,然后就可以单击“完成”了。然后就生成了如下图所示的一个项目结构: 

这个项目和通常 Eclipse的项目结构有点不同,不过这是一个现在非常流行的项目结构, src/java存放源文件, test/java存放相应的 JUnit单元测试代码。如果你用 Maven来编译构建项目,对这种目录结构一定不陌生。

 

项目创建起了,介绍一下里面的文件吧:

l          MessageActionHandler,自动生成的一个 ActionHandler。不想要可以删掉。

l          ehcache.xml cache的配置文件,里面有很详解的英文说明。没有必要可以不用改它。

l          hibernate.cfg.xml  jBPM是用 Hibernate进行工作流的数据存储的,这个就是 Hibernate的配置文件。后面我们将讲到如何配置这个文件。

l          jbpm.cfg.xml  jbpm本身的配置文件。现在是空的,它用的是缺省配置,你想知道有哪些配置就去看这个文件 D:/jbpm-starters-kit-3.1.1/jbpm.3/src/java.jbpm/org/jbpm/default.jbpm.cfg.xml

l          log4j.properties 这个是日志 API log4j的配置文件,用过 log4j的都知道。

l          SimpleProcessTest.java 这个是对最重要的流程配置文件的 processdefinition.xml单元测试代码。这里表扬一点, jBPM的优良设计使得它的可测试性非常之高,喜欢写 t单元测试的人有福了。

l          gpd.xml 用于生成流程图的定义文件。都是一些方框的坐标和长宽

l          processdefinition.xml 这个是对最重要的流程配置文件,以后写流程要经常和它打交道。

l          processimage.jpg 一个流程图


从项目结构来看,我们没有看到 JSP网页程序,也没有看到 GUI客户端程序,这些代码都是要我们以后开发中来写的。但本文不准备用 JSP GUI Swing SWT)来做示例,而是用 JUnit代码来做使用 jBPM客户端来演示。因为 jBPM实际上是一个后台框架,至于前台是 JSP还是 Swing还是无界面的 java.class都是无关紧要的。在教程里用无界面的 java.class来做客户端则更方便一些,如果进一步采用 JUnit,则这样的 java.class同时还具备了单元测试的功能。以后就是用 JSP写了 WEB页面,我们还是可以用这些 JUnit程序来做单元测试,避免了频繁的鼠标点按 WEB页面这样的力气活。所以在 jBPM自带的英文教程里都是一个 JUnit程序,不仔佃看还真摸不着头脑。

 

6.2 修改hibernate.cfg.xml

   hibernate.cfg.xml的默认设置是用 HSQL,这是一个内存数据库,这种内存数据库用来代替项目实际所用的数据库来做单元测试挺不错的。不过我们这里是要试试用 MySQL Oracle,那就改一下设置吧。

注:配置值可参考 D:/jbpm-starters-kit-3.1.1/jbpm-db对应子目录下的 hibernate.properties文件。

1 MySQL的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jbpm</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password">123456</property>

 

2 Oracle的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>

<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

<property name="hibernate.connection.url">jdbc:oracle:thin:@192.168.123.10:1521:wxxrDB</property>

<property name="hibernate.connection.username">chengang</property>

<property name="hibernate.connection.password">chengang</property>

 

如果你装了 Oracle的客户端,并且 D:/oracle/ora92/network/ADMIN/tnsnames.ora里做了如下的设置

WXXRDB_192.168.123.10 =

 (DESCRIPTION =

   (ADDRESS_LIST =

     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.123.10)(PORT = 1521))

   )

   (CONNECT_DATA =

     (SID = wxxrDB)

     (SERVER = DEDICATED)

   )

 )


Oracle hibernate.connection.url项也可以设为: jdbc:oracle:oci:@WXXRDB_192.168.123.10

 

6.3 完善库引用

   虽然 jBPM在创建项目之初给我们设置好了库引用,

但后面运行时还是报一些 NoClassDefFoundError异常,如没有对 hibernate3.jar的引用导致下面的错误

java.lang.NoClassDefFoundError: org/hibernate/Session

   at org.jbpm.persistence.db.DbPersistenceServiceFactory.openService(DbPersistenceServiceFactory.java:55)

   at org.jbpm.svc.Services.getService(Services.java:136)

   .......

 

所以我们要为本文的实例完善库引用。主要是把 MySQL Oracle JDBC库、以及 Hibernate hibernate3.jar加入到项目的库引用中。

1      找到缺少的 jar

l          mysql jdbc包,在 D:/jbpm-starters-kit-3.1.1/jbpm-db/mysql/lib目录里

l          oracle jdbc包, jbmp中没有包含(可能是没拿到 oracle授权),我们可以自已去 oracle网站上下载,或者去 oracle安装目录 D:/oracle/ora92/jdbc/lib ojdbc14.jar(我们公司用的是 Oracle9i

l          Hibernate3.jar在目录 D:/jbpm-starters-kit-3.1.1/jbpm.3/lib/hibernate里。

2      在项目里创建一个 lib目录,将这三个 jar复制到 lib目录。

3      如下图设置三 jar包的库引用

 

6.4 开始HellorWorld

这里是一个很简单的请假流程,请假人提交假单给经理审批,经理审批后结束。要说明的是,这个流程并不严谨,比如经理不通过流程应该到哪?不过这并不防碍拿它来做示例,螃蟹还得一个一个的吃。我们先拿这一杆子捅到底的流程做一个最简单的示例,从整体上对 jBPM 工作流开发有概念先。然后我们再慢慢丰富。

 

1 、定义流程

流程的定义文件是 processdefinition.xml,这个是一个关键文件, jBPM的很大一部份内容都是关于它的。在这里我们把原来自动生成的内容,稍做改动:

<?xmlversion="1.0"encoding="GBK"?>

 

<process-definitionxmlns="urn:jbpm.org:jpdl-3.1"name="helloworld">

   <!--申请-->

   <start-statename="request">

      <task>

          <controller>

             <variablename="name"/>

             <variablename="day"/>

             <variablename="note"/>

          </controller>

      </task>

      <!--流程转向-->

      <transitionname="to_confirm"to="confirm">

          <actionname="requestAction"

             class="cn.com.chengang.jbpm.RequestAction">

             <reason>我要请假</reason>

          </action>

      </transition>

   </start-state>

   <!--审批-->

   <statename="confirm">

      <transitionname="to_end"to="end">

          <actionname="finishAction"

             class="cn.com.chengang.jbpm.ConfirmAction" />

      </transition>

   </state>

   <!--结束-->

   <end-statename="end"/>

</process-definition>


说明:

流程的名称改成了 helloworld。(呵呵,也就是这里和 helloworld有关了)

<controller>标签定义了三个数据:姓名、请假天数、说明。

<transition>标签定了 request节点的一个流程转向,这里是转到 confirm节点。

<action>标签定义了流程由一个节点转到另一个节点时,所要执行的动作,动作封装在一个 ActionHandler类中。比如这里当 request confirm结点时将执行 RequestAction类的 execute方法。

FinishAction下面还有一个 <reason>(请假理由),它对应于 FinshAction的属性 String reason

 

2 、 编写 ActionHandler

   在上面 processdefinition.xml里我们定义了两个 ActionHandler RequestAction ConfirmAction。其代码如下:

packagecn.com.chengang.jbpm;

 

importorg.jbpm.graph.def.ActionHandler;

importorg.jbpm.graph.exe.ExecutionContext;

 

publicclassRequestActionimplements ActionHandler {

 

   private static final longserialVersionUID= 1L;

 

   privateString reason;

 

   publicString getReason() {

      returnreason;

   }

 

   publicvoid setReason(String reason) {

      this.reason = reason;

   }

 

   publicvoid execute(ExecutionContext context)throws Exception {

      context.getContextInstance().setVariable("note",reason);

   }

 

}

 

说明: ExecutionContext是一个贯通流程的容器。它是个大宝箱,里面啥玩意都有,后面将更深入的提到。这里的 reasion就是 processdefinition.xml中的我要请假

 

 

packagecn.com.chengang.jbpm;

 

importorg.jbpm.graph.def.ActionHandler;

importorg.jbpm.graph.exe.ExecutionContext;

publicclassConfirmActionimplements ActionHandler {

 

   private static final longserialVersionUID= 1L;

 

   publicvoid execute(ExecutionContext context)throws Exception {

      context.getContextInstance().setVariable("note","准假" );

   }

 

}

 

OK ,后台的程序就算写完了(前台客户端的程序还没写),下面开始部署。

 

6.5 部署processdefinition.xml

   我们要把 processdefinition.xml的流程定义的数据部署到数据库中,因为 jBPM在正式运行的时候不是去读 processdefinition.xml文件,而是去读数据库中的流程定义。  这里写了一个个 JUnit程序来部署 processdefinition.xml,当然你用普通的 Java Main也可以。

packagecom.sample;

 

importjava.io.FileInputStream;

importjava.io.FileNotFoundException;

importjava.io.InputStream;

 

importjunit.framework.TestCase;

 

importorg.jbpm.JbpmConfiguration;

importorg.jbpm.JbpmContext;

importorg.jbpm.graph.def.ProcessDefinition;

 

/**

 *部署processdefinition.xml

 *

 *@author chengang

 *

 */

publicclassDeployProcessTestextends TestCase {

   /**

    *在本方法执行完毕后,检查jbpm_processdefinition表会多了一条记录

    *

    *@throws FileNotFoundException

    */

   publicvoid testDeployProcessDefinition() throws FileNotFoundException {

      //jbpm.cfg.xml取得jbpm的配置

      JbpmConfiguration config = JbpmConfiguration.getInstance();

      //创建一个jbpm容器

      JbpmContextjbpmContext = config.createJbpmContext();

      //processdefinition.xml生成相对应的流程定义类ProcessDefinition

      InputStream is =new FileInputStream("processes/simple/processdefinition.xml");

      ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(is);

      //利用容器的方法将流程定义数据部署到数据库上

      jbpmContext.deployProcessDefinition(processDefinition);

      //关闭jbpmContext

      jbpmContext.close();

   }

 

}

 

运行此程序,在控制台打印了一些日志,通过。如果出错,仔佃阅读出错信息以判断错误原因,并确定你按照前面两节:“修改 hibernate.cfg.xml”和“完善库引用”的内容做好了设置。

如果报Named query not known: GraphSession.findLatestProcessDefinitionQuery,则需要将jbpm的hibernate映射文件引入hibernate.cfg.xml

 

	<mapping resource="org/jbpm/bytes/ByteArray.hbm.xml"/>
	<mapping resource="org/jbpm/command/ExecuteActionCommand.hbm.xml"/>
	<mapping resource="org/jbpm/command/ExecuteNodeCommand.hbm.xml"/>
	<mapping resource="org/jbpm/command/SignalCommand.hbm.xml"/>
	<mapping resource="org/jbpm/command/TaskInstanceEndCommand.hbm.xml"/>
	<mapping resource="org/jbpm/context/def/ContextDefinition.hbm.xml"/>
	<mapping resource="org/jbpm/context/def/VariableAccess.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/ContextInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/TokenVariableMap.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/NullInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/exe/VariableInstance.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/VariableCreateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/VariableDeleteLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/VariableLog.hbm.xml"/>
	<mapping resource="org/jbpm/context/log/VariableUpdateLog.hbm.xml"/>
	<mapping resource="org/jbpm/db/hibernate.queries.hbm.xml"/>
	<mapping resource="org/jbpm/file/def/FileDefinition.hbm.xml"/>
	<mapping resource="org/jbpm/graph/action/Script.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/Action.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/Event.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/ExceptionHandler.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/Node.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/ProcessDefinition.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/SuperState.hbm.xml"/>
	<mapping resource="org/jbpm/graph/def/Transition.hbm.xml"/>
	<mapping resource="org/jbpm/graph/exe/Comment.hbm.xml"/>
	<mapping resource="org/jbpm/graph/exe/ProcessInstance.hbm.xml"/>
	<mapping resource="org/jbpm/graph/exe/RuntimeAction.hbm.xml"/>
	<mapping resource="org/jbpm/graph/exe/Token.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/ActionLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/NodeLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/ProcessStateLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/SignalLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/TokenCreateLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/TokenEndLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/log/TransitionLog.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/Decision.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/EndState.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/Fork.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/Join.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/ProcessState.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/StartState.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/State.hbm.xml"/>
	<mapping resource="org/jbpm/graph/node/TaskNode.hbm.xml"/>
	<mapping resource="org/jbpm/instantiation/Delegation.hbm.xml"/>
	<mapping resource="org/jbpm/logging/log/CompositeLog.hbm.xml"/>
	<mapping resource="org/jbpm/logging/log/MessageLog.hbm.xml"/>
	<mapping resource="org/jbpm/logging/log/ProcessLog.hbm.xml"/>
	<mapping resource="org/jbpm/module/def/ModuleDefinition.hbm.xml"/>
	<mapping resource="org/jbpm/module/exe/ModuleInstance.hbm.xml"/>
	<mapping resource="org/jbpm/msg/db/TextMessage.hbm.xml"/>
	<mapping resource="org/jbpm/msg/Message.hbm.xml"/>
	<mapping resource="org/jbpm/scheduler/def/CancelTimerAction.hbm.xml"/>
	<mapping resource="org/jbpm/scheduler/def/CreateTimerAction.hbm.xml"/>
	<mapping resource="org/jbpm/scheduler/exe/Timer.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/def/Swimlane.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/def/Task.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/def/TaskController.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/exe/PooledActor.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml"/>
	<mapping resource="org/jbpm/taskmgmt/log/TaskLog.hbm.xml"/>


 

 (如果抛出异常09:32:43,791 [main] ERROR ErrorCounter : *** ERROR: line 3:45: expecting "set", found 't'
09:32:43,822 [main] ERROR ErrorCounter : *** ERROR: line 3:45: expecting "set", found 't'
09:32:43,869 [main] ERROR ErrorCounter : *** ERROR: line 3:50: unexpected token: t
09:32:43,931 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.deleteTimersForProcessInstance
org.hibernate.hql.ast.QuerySyntaxError: unexpected token: t near line 3, column 50 [
     
        delete from org.jbpm.scheduler.exe.Timer t
        where t.processInstance = :processInstance
     
    ]
 at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
 at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
 at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
 at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
 at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
 at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
 at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
 at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
 at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
 at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
 at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
 at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
 at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
 at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:324)
 at junit.framework.TestCase.runTest(TestCase.java:154)
 at junit.framework.TestCase.runBare(TestCase.java:127)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:50: unexpected token: t
 at org.hibernate.hql.antlr.HqlBaseParser.deleteStatement(HqlBaseParser.java:242)
 at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:139)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
 ... 28 more
09:32:43,947 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.suspendTimersForToken
org.hibernate.hql.ast.QuerySyntaxError: expecting "set", found 't' near line 3, column 45 [
     
        update org.jbpm.scheduler.exe.Timer t
        set t.isSuspended = true
        where t.token = :token
     
    ]
 at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
 at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
 at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
 at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
 at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
 at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
 at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
 at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
 at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
 at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
 at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
 at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
 at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
 at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:324)
 at junit.framework.TestCase.runTest(TestCase.java:154)
 at junit.framework.TestCase.runBare(TestCase.java:127)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:45: expecting "set", found 't'
 at antlr.Parser.match(Parser.java:211)
 at org.hibernate.hql.antlr.HqlBaseParser.setClause(HqlBaseParser.java:337)
 at org.hibernate.hql.antlr.HqlBaseParser.updateStatement(HqlBaseParser.java:183)
 at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:133)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
 ... 28 more
09:32:43,947 [main] ERROR SessionFactoryImpl : Error in named query: SchedulerSession.resumeTimersForToken
org.hibernate.hql.ast.QuerySyntaxError: expecting "set", found 't' near line 3, column 45 [
     
        update org.jbpm.scheduler.exe.Timer t
        set t.isSuspended = false
        where t.token = :token
     
    ]
 at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:63)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:215)
 at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:127)
 at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:83)
 at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
 at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:388)
 at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
 at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1005)
 at org.jbpm.persistence.db.DbPersistenceServiceFactory.getSessionFactory(DbPersistenceServiceFactory.java:93)
 at org.jbpm.persistence.db.DbPersistenceService.getSessionFactory(DbPersistenceService.java:74)
 at org.jbpm.persistence.db.DbPersistenceService.getSession(DbPersistenceService.java:78)
 at org.jbpm.persistence.db.DbPersistenceService.getGraphSession(DbPersistenceService.java:201)
 at org.jbpm.JbpmContext.getGraphSession(JbpmContext.java:427)
 at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:166)
 at com.hanxr.jbpm.action.DeployProcessTest.testDeployProcessDefinition(DeployProcessTest.java:35)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:324)
 at junit.framework.TestCase.runTest(TestCase.java:154)
 at junit.framework.TestCase.runBare(TestCase.java:127)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: line 3:45: expecting "set", found 't'
 at antlr.Parser.match(Parser.java:211)
 at org.hibernate.hql.antlr.HqlBaseParser.setClause(HqlBaseParser.java:337)
 at org.hibernate.hql.antlr.HqlBaseParser.updateStatement(HqlBaseParser.java:183)
 at org.hibernate.hql.antlr.HqlBaseParser.statement(HqlBaseParser.java:133)
 at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:209)
 ... 28 more
则修改JBossIDE-1.5.1.GA-ALL/eclipse/plugins/org.jbpm.core_3.0.8.1/build/jbpm-3.1-beta3.jar/org/jbpm/db/hibernate.queries.hbm.xml文件

  <query name="SchedulerSession.deleteTimersForProcessInstance">
      <![CDATA[
        delete from org.jbpm.scheduler.exe.Timer t
        where t.processInstance = :processInstance
      ]]>
    </query>

    <query name="SchedulerSession.suspendTimersForToken">
      <![CDATA[
        update org.jbpm.scheduler.exe.Timer t
        set t.isSuspended = true
        where t.token = :token
      ]]>
    </query>

    <query name="SchedulerSession.resumeTimersForToken">
      <![CDATA[
        update org.jbpm.scheduler.exe.Timer t
        set t.isSuspended = false
        where t.token = :token
      ]]>
    </query>

改为:
  <query name="SchedulerSession.deleteTimersForProcessInstance">
      <![CDATA[
        delete from org.jbpm.scheduler.exe.Timer
        where processInstance = :processInstance
      ]]>
    </query>

    <query name="SchedulerSession.suspendTimersForToken">
      <![CDATA[
        update org.jbpm.scheduler.exe.Timer
        set isSuspended = true
        where token = :token
      ]]>
    </query>

    <query name="SchedulerSession.resumeTimersForToken">
      <![CDATA[
        update org.jbpm.scheduler.exe.Timer
        set isSuspended = false
        where token = :token
      ]]>
    </query>

)

6.6 从数据库中的查看部署效果

无论是 MySQL还是 Oracle,查询 jbpm_processdefinition表,你会发现多了一条记录,如下图 ( PLSQL Developer的显示为例 )

依次检查各表我们可以发现有如下变化:




并由此简单判断出各表的作用,表中各字段的作用由字段名也能知晓一二。

jbpm_processdefinition

一个流程定义文件对应一条记录,可记录多个流程定义文件,可记录一个流程定义文件的对个版本。

jbpm_action

记录 ActionHandler的对象实例(以名称为标识)

jbpm_delegation

记录了 ActionHandler全类名,以便于用反射方式来加载

jbpm_event

它的 transition引用了 Jbpm_transition表的 id,再看其它字段,估计此表是表示流程转向事件的一个实例,或者是一个各表之间的联接表。

jbpm_node

流程结点

jbpm_transition

流程的转向定义

jbpm_variableaccess

流程中携带的变量。 ACCESS字段是这些变量的读写权限

 

jBPM 的客户端开发

有了前面的 HelloWorld后台流程,我们就要开始客户端程序了。正如前面提到的,本文不写 JSP,而改采用 JUnit的形式,输出则用 System.out.println。举一反三,知道在方法中输入及用 println输出,在 JSP SWING GUI界面还不是一样嘛。

 

这个 JUnit客户端,我们就借用创建项目时自动生成的 SimpleProcessTest.java了,改写后如下:

packagecom.sample;

 

importjunit.framework.TestCase;

 

importorg.jbpm.JbpmConfiguration;

importorg.jbpm.JbpmContext;

importorg.jbpm.context.exe.ContextInstance;

importorg.jbpm.graph.def.ProcessDefinition;

importorg.jbpm.graph.exe.ProcessInstance;

 

public class SimpleProcessTest extends TestCase {

 

   private JbpmConfiguration config = JbpmConfiguration.getInstance();

   private JbpmContext ctx = config.createJbpmContext();

   // helloworld对应于jbpm_processdefinition表的name字段值,也即processdefinition.xmlname

   //这个值得取比较耗时,实际项目里最好和“数据库的JDBC连接”一样,让它共享,不要频繁打开关闭。

   private ProcessDefinition processDefinition = ctx.getGraphSession().findLatestProcessDefinition("helloworld");

 

   publicvoid testNewRequest() {

      longid = newRequest();

      System.out.println("id=" + id);

      checkNewRequest(id);

      confirmRequest(id);

      checkconfirmRequest(id);

      ctx.close();//关闭jbpm容器

   }

 

   /**

    * 创建一个请假单

    *

    * @return

    */

   privatelong newRequest() {

      //创建一个新流程

      ProcessInstance pi =processDefinition.createProcessInstance();

      //取得流程的数据环境

      ContextInstance ci = pi.getContextInstance();

      //创建一张请假单

      ci.setVariable("name","陈刚www.chengang.com.cn" );

      ci.setVariable("day", 2);

      assertEquals(null, ci.getVariable("note"));

      //请假申请结束,转到下一个流程结点

      pi.signal();

      returnpi.getId();

   }

 

   /**

    * 检查请假单的数据

    *

    * @paramid

    */

   privatevoid checkNewRequest(long id) {

      //从数据库提取原流程

      ProcessInstance pi =ctx.loadProcessInstance(id);

      //取得流程的数据环境

      ContextInstance ci = pi.getContextInstance();

      //创建一张请假单

      assertEquals("陈刚www.chengang.com.cn" , ci.getVariable("name"));

      assertEquals(Integer.valueOf(2), ci.getVariable("day"));

      assertEquals("我要请假" , ci.getVariable("note"));

 

      //当前是结点为confirm

      assertEquals(pi.getRootToken().getNode().getName(),"confirm");

      //流程还没结束

      assertFalse(pi.hasEnded());

   }

 

   /**

    * 审批陈刚的请假申请

    *

    * @paramid

    */

   privatevoid confirmRequest(long id) {

      ProcessInstance pi =ctx.loadProcessInstance(id);

      ContextInstance ci = pi.getContextInstance();

      //不通过

      ci.setVariable("note","不准请假,继续加班" );

      //审批结束,到下一个流程结点

      pi.signal();

   }

 

   privatevoid checkConfirmRequest(long id) {

      ProcessInstance pi =ctx.loadProcessInstance(id);

      ContextInstance ci = pi.getContextInstance();

      // ConfirmAction类在signal后执行,所以覆盖了经理的审批意见

      assertEquals("准假" , ci.getVariable("note"));

 

      //当前是结点为end

      assertEquals(pi.getRootToken().getNode().getName(),"end");

      //流程结束了

      assertTrue(pi.hasEnded());

   }

 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值