The important thing in life is to have a great aim , and the determination

常用链接

统计

IT技术链接

保险相关

友情链接

基金知识

生活相关

最新评论

对Jbpm数据库应用的简单分析和在Mysql上实现的demo

Jbpm 数据库应用的简单分析和在 Mysql 上实现的 demo

 

吴大愚

dywu_xa@sina.com

2006-10-17

 

 

适用 jbpm3.1 版本

 

HelloWorldDbTest 的分析

Eclipse 中到如 jbpm-starters-kit-3.1\jbpm 工程后,在 src\examples\org\jbpm\db 底下有一个 HelloWorldDbTest.java 的实例。我从这个实例分析开始,构建自己的 jbpm 工程在 Mysql 下的应用。

首先我们来先分析一下 HelloWorldDbTest 实例。

基本流程

HelloWorldDbTest 类是一个 JUnit 的测试类。里面只有一个测试函数 testSimplePersistence 。这个函数里面调用了三个操作,分别是:

l          将流程( processDefinition )的部署到数据库中;

l          从数据库中加载流程,并实例化一个流程实例( processInstance ),然后运行一半再将流程实例存回数据库;

l          从数据库中加载流程实例,然后运行完毕这个实例。

JbpmConfigration

在类 HelloWorldDbTest 中有静态代码段,内容是构造一个 JbpmConfigration 的实例。 JbpmConfigration Jbpm3.1 中和 Jbpm3 中差别很大, JbpmAPI 手册描写如下:

configuration of one jBPM instance. During process execution, jBPM might need to use some services. A JbpmConfiguration contains the knowledge on how to create those services.

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.

JbpmConfigration 主要有两种加载方法,一种是从配置文件中加载,一般使用 jbpm.cfg.xml jbpm-starters-kit-3.1 中放在 jbpm-starters-kit-3.1\jbpm\src\config.files 目录下。要使用 jbpm.cfg.xml 进行配置的话,就必须把这个文件放在 classpath 中。因为 jbpm-starters-kit-3.1\jbpm 工程已经把此目录放在工程的 classpath 中,所以如果在代码中 JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(); 这样书写的话就是使用 jbpm.cfg.xml 中的配置来构造 JbpmConfigration 。另外一种就是本例中使用的对 xml 解析的方法。

使用数据库

在加载的 JbpmConfiguration 的加载内容中有如下部分:

"  <string name='resource.hibernate.cfg.xml' " +

      "          value='hibernate.cfg.xml' />" +

这里面的 hibernate.cfg.xml 也在 jbpm-starters-kit-3.1\jbpm\src\config.files 目录下,是对 Jbpm 使用的 Hibernate 的配置文档。通过这个文档, Jbpm 就可以通过 Hibernate 的工具,在不同的数据库中,把说使用到的表全部构建出来,而不需要再人工去操作 sql 语句在数据库中操作,这也就是为什么这个实例中没有需要我们自己在数据库中建表建库的原因。

通过 HelloWorldDbTest 类的注释和用户手册中的文档可以知道,在这个实例中使用的数据库是一个内存数据库,在目录下的 Hibernate.cfg.xml 中有如下内容:

    <!-- jdbc connection properties -->

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

    < property name = "hibernate.connection.driver_class" > org.hsqldb.jdbcDriver </ property >

    < property name = "hibernate.connection.url" > jdbc:hsqldb:mem:.;sql.enforce_strict_size=true </ property >

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

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

 

懂得 Hibernate 的朋友就能看出来,在 jbpm 工程中,使用的数据库是 hsqldb

在加载 HelloWorldDbTest 类的时候,就会发现,在 console 有大量的输出。其中包括:

12:27:38,201 [main] INFO  Configuration : Reading mappings from resource: org/jbpm/graph/def/Transition.hbm.xml

12:27:38,231 [main] INFO  HbmBinder : Mapping class: org.jbpm.graph.def.Transition -> JBPM_TRANSITION “很多类似的输出。这些输出就是 Hiernate 在加载描述文件时候产生的说明信息。

输出信息中后面还包括对数据库的连接,设置等等说明信息。

 

JbpmConfiguration.createSchema()

这个方法可以实现自动在数据库中生成表结构的。在这个实例中,在 Junit   setup() 操作中调用了这个函数,在进行测试实例前对数据库进行创建。

JbpmContext

运行 HelloWorldDbTest 中的测试实例。

首先是定义一个流程,然后就实例化一个 JbpmContext

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

JbpmContext 类是 Jbpm3.1 版本引进的一个新类,以前是没有的。

jbpm 的说明中有对 JbpmContext 类的如下说明:

JbpmContext is used to surround persistent operations to processes.

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, ...

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.

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有个大致的了解。最主要的就是实现Jbpm对数据库操作的所有接口的封装。

流程部署

deployProcessDefinition 中的 jbpmContext. deployProcessDefinition (processDefinition); 操作,向数据库中部署一个流程。如果跟踪 deployProcessDefinition 的话,会发现 jbpmContext 还是调用的 GraphSession 的流程部署方法。后面我们再讲到 GraphSession 类。

在后面使用 Mysql 实现的例子中,我们就可以通过工具在 mysql 中看到这样一个部署流程的操作对数据库有如何影响。同样也可以查看流程实例化保存在数据库中的情况。

GraphSession

Jbpm are the graph related database operations 的类。可以通过 GraphSession graphSession = jbpmContext.getGraphSession(); 来得到这个类的实例,并且 JbpmContext 很多方法都是封装该类的方法。

该类中包括了几乎所有的数据库操作的,例如部署流程,加载流程,部署流程实例,加载变量,等等。

 

HelloWorldDbTest 类本身就已经有非常完整的注释, 有关分析也就写到这里。

 

Jbpm Mysql 上的 demo 工程

创建 Jbpm Project

首先在 Eclipse 里面创建一个 Jbpm Process Project 的新项目。比如命名为 myDemo Eclipse Jbpm 插件会自动创建一些文件,比如在 processes 目录下有一个 simple 的流程。在 src/java 下面有一个 MessageActionHandler 的类。在 src/config.files 目录下四个配置有文件。在 test/java 下面有一个 SimpleProcessTest JUnit 类实例。可以先运行这个测试,应该是正确没有问题的。

配置 Mysql 数据库

打开 MySql 数据库,假设 MySql 数据库的用户名为 root ,密码 1234 。首先创建 jbpm_db 数据库。然后修改 src/config.files 底下的 Hibernate.cfg.xml 文件。将连接数据库的部分换成 Mysql 的内容。如下:

        <!-- jdbc connection properties -->

    < 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_db </ property >

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

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

添加代码和流程

我们先创建一个自己的流程。在 processes 目录下面创建一个叫做 pro1 的流程。然后添加最简单的, start-state ,end 和一个 state 节点。

Jbpm3 工程中的 jbpm.cfg.xml 中的内容添加到 src/config.files 目录下的 jbpm.cfg.xml 中。

test/java 目录下面添加一个新的 Junit 类。命名为 SimpleDBTest

代码如下:

package com.sample;

 

import java.io.FileInputStream;

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 SimpleDBTest extends TestCase {

       static JbpmConfiguration cfg = JbpmConfiguration.getInstance();    

       public void setUp() {

          cfg.createSchema();

       }    

       public void testDeployProcessDefinition() throws Exception {

              assertNotNull("JbpmConfiguration should not be null", cfg);

                           

              FileInputStream fis = new FileInputStream("processes/pro1/processdefinition.xml");

              ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(fis);

              assertNotNull("Definition should not be null", processDefinition);

         

              JbpmContext jbpmContext = cfg.createJbpmContext() ;

             

              try {

               // Deploy the process definition in the database

               jbpmContext.deployProcessDefinition(processDefinition);

             } finally {

               jbpmContext.close();

             }

       }

}

执行这个操作,会发现报错,报不能找到 Hibernate 的错误。原来在 Eclipse 建立的 Jbpm 的工程中,虽然添加了 Jbpm 的包,但没有添加 Hibernate 的包。因此在工程的 Java Build Path Libraries 底下添加 Hibernate 的包(具体添加那些,请参考 Jbpm 的用户手册)。

部署流程

执行 SimpleDBTest .testDeployProcessDefinition() 操作。如果没有错误的话,这次就可以将流程 pro1 部署进入 Mysql 数据库。

jbpm_db 数据库中会看到产生了 33 个表。查看 jbpm_processdefinition 表,会发现有一个名字为 pro1 ID 1 version 1 的条目。

同样可以查看 jbpm_node 表。

再次部署

修改流程 pro1 的定义,在 state1 节点添加一个 Action ,在 node-enter 事件中。完整的 xml 文件见该文档最后部分。然后再次运行 SimpleDBTest .testDeployProcessDefinition() 操作。查看 jbpm_processdefinition ,会发现有了一个 pro1 version 2 版本的流程。这里有了一个 Jbpm 流程版本的概念,可以参考用户手册。

还可查看 jbpm_event jbpm_action 表。

实例化流程

添加代码:

       public void testLoadProcessAndInstance() throws Exception {

              JbpmContext jbpmContext = cfg.createJbpmContext() ;           

              try {

                    GraphSession graphSession = jbpmContext.getGraphSession();                 

                    ProcessDefinition processDefinition =

                        graphSession.findLatestProcessDefinition("pro1");            

                    ProcessInstance processInstance =

                        new ProcessInstance(processDefinition);

                    Token token = processInstance.getRootToken();

                    assertEquals("start", token.getNode().getName());

                    // Let's start the process execution

                    token.signal();

                    assertEquals("state1", token.getNode().getName());

                   

                    jbpmContext.save(processInstance);

 

                  } finally {

                    // Tear down the pojo persistence context.

                    jbpmContext.close();

                  }

       }

这段代码把 pro1 流程的最新版本加载进来,然后实例化。并开始执行,到 state1 节点停下来(此时 Action 已经执行过了)。然后把这个实例也存入数据库。

这时候查看 jbpm_processInstance 表, jbpm_token 表。

完成实例的运行

添加代码

public void testLoadInstanceAndDoActionAndEnd() throws Exception {

              JbpmContext jbpmContext = cfg.createJbpmContext() ;           

                try {

                    GraphSession graphSession = jbpmContext.getGraphSession();

                 

                    ProcessDefinition processDefinition =

                        graphSession.findLatestProcessDefinition("pro1");

                    List processInstances =

                        graphSession.findProcessInstances(processDefinition.getId());                  

      

                    ProcessInstance processInstance =

                        (ProcessInstance) processInstances.get(0);                 

                    this.assertEquals("message",(String)(processInstance.getContextInstance().getVariable("message")));

                    processInstance.signal();

                    assertTrue(processInstance.hasEnded());

                    jbpmContext.save(processInstance);

                  } finally {

                    jbpmContext.close();

                  }

       }

这段代码将刚才的流程实例从数据库中加载进来,然后执行完毕。

查看表 jbpm_processinstance 表,会发现上次 end 字段还是 null ,现在已经是填写了刚才执行的事件了,表示这个流程实例已经执行完毕。

流程 Pro1 的完整 xml 文档

<? xml version = "1.0" encoding = "UTF-8" ?>

 

< process-definition

  xmlns = "urn:jbpm.org:jpdl-3.1"  name = "pro1" >

   < start-state name = "start" >

      < transition name = "" to = "state1" ></ transition >

   </ start-state >

   < state name = "state1" >

      < event type = "node-enter" >

         < action name = "action1" class = "com.sample.action.MessageActionHandler" >

            < message > message </ message >

            < message2 > message2 </ message2 >

         </ action >

      </ event >

      < transition name = "" to = "end" ></ transition >

   </ state >

   < end-state name = "end" ></ end-state >

</ process-definition >

总结

posted on 2006-12-04 17:12 鸿雁 阅读(253) 评论(0)  编辑  收藏