jBPM3.12用户指南中文翻译----第三章 指南

   这是Jboss 的jBPM3.12框架的用户指南的中文翻译。我的翻译风格是中英文对照,只翻译部分我认为重要的,不翻译简单的英文,以免浪费你我的时间。
       同时,对于其中的部分内容,我会在翻译中做出解释和写上我的理解。


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流程定义文件。

 

3.1. Hello World example

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过程定义的图形化表示。

V:SHAPE id=_x0000_i1025 style="WIDTH: 63.75pt; HEIGHT: 120pt" type="#_x0000_t75"><!--[if !vml]--><!--[endif]-->

<!--[if !vml]-->The hello world process graph<!--[endif]-->

Figure 3.1. The hello world process graph

Hello world业务处理图表

  publicvoid 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工作处理定义类的一个实例创建。代表一个工作处理定义的执行。主要关注于工作处理相关的操作。

 

getRootToken

public TokengetRootToken()

    得到工作处理定义的从start状态开始的一条记号----工作流程。

 

 

findToken

public TokenfindToken(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.

在工作处理定义的树中,根据记号路径/工作流程路径得到一条工作流程

 

 

3.2. Database example

数据库例子

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能够被用来为所有的线程创建JbpmContextJbpmConfiguration.createJbpmContext();方法创建Jbpm上下文环境类的一个实例。

JbpmConfiguration应该使用单例,如静态成员,或者JNDI树,或者IOC容器管理的单例等。

A JbpmConfiguration can be obtained in following ways:

  • from a resource (by default jbpm.cfg.xml is used):

<!--[if !supportLists]-->·                <!--[endif]--> JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();

 

or

 String myXmlResource = "...";

 JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance(myXmlResource);

  • from an XML string:

<!--[if !supportLists]-->·                <!--[endif]--> JbpmConfiguration jbpmConfiguration = JbpmConfiguration.parseXmlString(

<!--[if !supportLists]-->·                <!--[endif]-->   "" +

<!--[if !supportLists]-->·                <!--[endif]-->   ...

<!--[if !supportLists]-->·                <!--[endif]-->   ""

<!--[if !supportLists]-->·                <!--[endif]--> );

 

  • By specifying a custom implementation of an object factory. This can be used to specify a JbpmConfiguration in other bean-style notations such as used by JBoss Microcontainer or Spring.

通过指定一个对象工厂的定制实现。被用在JBoss或者Spring容器中。

 

<!--[if !supportLists]-->·                <!--[endif]--> ObjectFactory of = new MyCustomObjectFactory();

<!--[if !supportLists]-->·                <!--[endif]--> JbpmConfiguration.Configs.setDefaultObjectFactory(of);

<!--[if !supportLists]-->·                <!--[endif]--> 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

 

 

 

2Jbpm上下文环境

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()调用时被自动保存到数据库中。

 

3GraphSession  业务处理图表会话类,更确切的名字:业务处理定义  会话类

 

 

 

/*

 * 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., 51 Franklin St, Fifth Floor, Boston, MA

 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.

 */

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();

 

    // Suppose we want to start a process instance (=process execution)

    // when a user submits a form in a web application...

    /*假设当一个用户提交一个表单时,我们要开始一个业务处理的实例/执行。

     * 这可以在Action中执行处理。

     */

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

      /*

       * 这个方法把业务处理定义通过Hibernate保存到数据库中。

       *

       * */

    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.

       /*

        * 关闭jbpm上下文。删除pojo持久化上下文。

        * 这包括刷新SQL来真正的把业务处理定义插入到数据库中。

        * */

      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 {

/*

 * 图表会话,是图表定义/业务处理定义 相关的数据库层面的会话。应该也是一个Hibernate会话。

 * 可以从JBpm上下文这个数据库----业务处理定义、实例等 得到 业务处理定义会话。

 *

 * */

      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保存这个业务处理实例进数据库。

       *    所以现在就把业务处理实例的执行状态也保存进了数据库。

       *  因为,业务处理定义的实例  这个类也是一个Model类,用于管理一个业务处理定义的执行的所有信息,

       *  是一个多例模式的Model

       *

       * */

      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.

    //这个方法可能在消息驱动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, we search for all process instances of this process definition.

      /*

       * 根据业务处理定义的id得到数据库中所有的业务处理实例。这表明,数据库中应该存在2张表

       * 它们是  一对多  的关系。

       *

       * */

      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();

    }

  }

}

 

3.3. Context example: process variables

上下文例子:处理变量

The process variables contain the context information during process executions. The process variables are similar to a java.util.Map that maps variable names to values, which are java objects. The process variables are persisted as a part of the process instance. To keep things simple, in this example we only show the API to work with variables, without persistence.

ContextInstance类的实例保存ProcessInstance中。是它的一个成员对象。是一个Map,保存名值对。它们会被保存在数据库中。 应该是一个独立的表。和业务处理定义的实例/执行表 是“一对多”的关系!

     可以在这里保存一些必要的信息,用于工作流程处理的交流的需要!

More information about variables can be found in Chapter 10, Context

publicclass ContextTest extends TestCase {

 

  publicvoid testContext() {

    // Also this example 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 variableInstances.

    //得到一个map,业务处理实例的上下文实例Map。包含业务处理实例的一些上下文信息。

    ContextInstance contextInstance =

      processInstance.getContextInstance();

   

    // Before the process has left the start-state,

    // we are going to set some process variableInstances in the

    // context of the process instance.

    contextInstance.setVariable("amount", new Integer(500));

    contextInstance.setVariable("reason", "i met my deadline");

   

    // From now on, these variableInstances are associated with the

    // process instance.  The process variableInstances are now accessible

    // by user code via the API shown here, but also in the actions

    // and node implementations.  The process variableInstances are also 

    // stored into the database as a part of the process instance.

   

    processInstance.signal();

   

    // The variableInstances are accessible via the contextInstance.

   

    assertEquals(new Integer(500),

                 contextInstance.getVariable("amount"));

    assertEquals("i met my deadline",

                 contextInstance.getVariable("reason"));

  }

 

}

 

 3.4. Task assignment example任务委派例子

In the next example we'll show how you can assign a task to a user. Because of the separation between the jBPM workflow engine and the organisational model, an expression language for calculating actors would always be too limited. Therefore, you have to specify an implementation of AssignmentHandler for including the calculation of actors for tasks.

    在下一个例子中,我们将高叔你怎样给一个用户分配任务。因为jBPM工作流引擎和组织的模型时各自独立的,用一种表达式语言来计算动作执行者总是太受限了。因此,你必须指定一个分派处理器的实现来包括任务执行者的计算工作。

API参考:

1,任务实例

public class TaskInstance

extends VariableContainer

implements Assignable

is one task instance that can be assigned to an actor (read: put in someones task list) and that can trigger the coninuation of execution of the token upon completion.

是一个任务实例,它能够被分配给一个用户,能够触发工作流的继续执行。

 

publicclass TaskAssignmentTest extends TestCase {

 

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

      /*

       * 任务节点是一个JPDL的节点,它表示一个等待状态,生成任务被完成之前,业务处理将不能执行。

       *

       * */

    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.

    /*

     * 执行到任务时,需要执行指定的类。这个类设置了执行者的id

     *     在真实环境中,应该是从数据库中返回任务,

     *     org.jbpm.db.TaskMgmtSession

     * TaskInstance包含:id,任务名,用户id

     * 业务处理实例---任务

     *            1  n

     *

     * 用户-------====任务

     *           1   n

     *

     * */

    TaskInstance taskInstance = (TaskInstance) 

        processInstance

          .getTaskMgmtInstance()

          .getTaskInstances()

          .iterator().next();

 

    // Now, we check if the taskInstance was actually assigned to 'papa'.

    assertEquals("papa", taskInstance.getActorId() );

   

    // Now suppose that 'papa' has done his duties and marks 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());

  }

 

}

 3.5. Custom action example定制动作例子

Actions are a mechanism to bind your custom java code into a jBPM process. Actions can be associated with its own nodes (if they are relevant in the graphical representation of the process). Or actions can be placed on events like e.g. taking a transition, leaving a node or entering a node. In that case, the actions are not part of the graphical representation, but they are executed when execution fires the events in a runtime process execution.

We'll start with a look at the action implementation that we are going to use in our example : MyActionHandler. This action handler implementation does not do really spectacular things不是真的做伟大的事情... it just sets the boolean variable isExecuted to true. The variable isExecuted is static so it can be accessed from within the action handler as well as from the action to verify it's value.

More information about actions can be found in Section 9.5, “Actions”

// MyActionHandler represents a class that could execute

// some user code during the execution of a jBPM process.

publicclass ActionTest extends TestCase {

 

  // Each test will start with setting the static isExecuted

  // member of MyActionHandler to false.

  publicvoid setUp() {

    MyActionHandler.isExecuted = false;

  }

 

  publicvoid 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 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);

  }

The next example shows the same action, but now the actions are placed on the enter-node进入节点事件 and leave-node events 离开节点事件respectively. Note that a node has more then one event type in contrast to a transition, which has only one event. Therefore actions placed on a node should be put in an event element.

Transition转向只有一个节点。

 

  publicvoid testNodeActions() {

    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);

  }

}

 

 

动作类

publicclass MyActionHandler implements ActionHandler {

 

  privatestaticfinallongserialVersionUID = 1L;

 

  // Before each test (in the setUp), the isExecuted member

  // will be set to false.

  publicstaticbooleanisExecuted = false; 

 

  // The action will set the isExecuted to true so the

  // unit test will be able to show when the action

  // is being executed.

  publicvoid execute(ExecutionContext executionContext) {

    isExecuted = true;

  }

}

 

API参考:

1

ExecutionContext  执行上下文类。

作为参数回调模式的参数,用于得到业务处理实例的东西。

 JbpmContext

getJbpmContext()
           

 Node

getNode()
           

 ProcessDefinition

getProcessDefinition()
           

 ProcessInstance

getProcessInstance()
           

可以通过它得到所有“业务处理”相关的对象。



posted on 2006-10-08 18:19 nbt 阅读(1472) 评论(0)  编辑  收藏 所属分类: workflow


只有注册用户登录后才能发表评论。


网站导航:
 
<2006年10月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

文章分类

文章档案

相册

收藏夹

Java技术网站

友情链接

国内一些开源网站

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜