{翻译 : jBPM5 : Chapter 4. Core Engine: API}

李渊 发布于 2012/03/09 08:00
阅读 689
收藏 1

题外话。小弟大四,四级未过,你懂的。要翻译一个项目的文档,最好是那些本来就精通这个项目的人。像jBPM5,当然要jBPM5专家来翻译。理由是翻译要么侧重直译的,要么自己理解一遍再将自己理解的写下来。这两种翻译各有优缺点,需要平衡。专家能更好的平衡。而我,刚学jBPM5,为了将jBPM5的概念理解好,才翻译之。之间,我有些不明白的,我会给出原文。共同学习。

jBPM5的官网刚好访问不了。原文地址,自己google。



本章介绍加载和执行流程时所需要的API。更多关于如何定义流程的内容,尽在BPMN 2.0章节。


与流程引擎交互,你需要建立一个会话(session)。此会话将用于与流程引擎的通信。会话必须有一个对知识库(knowledge base 的引用。知识库中又包含了所有与之相关的流程定义。在会话需要之时,知识库被用于查找流程的定义。在建立会话之前,你需要首先创建一个知识库,加载所有必须的流程定义(process definition)(可以是各种各样的加载源,如类路径、文件系统或者流程仓储),然后才能实例化一个会话。


一旦建立起一个会话,你可以使用它来启动执行流程。一个流程被启动时,一个新的流程实例被创建。这个新的流程实例用于维护具体流程的状态。



举个例子。想像你现在正在开发一个处理销售订单的应用程序。于是,你定义了一个或多个关于如何处理订单的流程定义。启动你的应用程序时,首先你必须创建一个包含了订单流程定义的知识库。然后,你就可以基于此知识库创建一个会话。当一个新的订单到来时,一个新的流程实例会被启动以处理之。该流程实例包含具体订单请求的流程状态。

在启动了的应用程序里,一个知识库只要创建一次,就可以在多个会话之间共享(创建一个知识库是十分重型的,因为这个过程包括解析和编译流程定义)。知识库可以动态变化(所以你可以在运行时添加或移除流程)。

会话可基于知识库创建,然后被用于执行流程及与引擎交互。如果需要,你可以创建多个独立的会话,也可以创建相对轻型的会话。创建多少个会话,由你决定。在你应用程序中,会话通常是一处创建多处被调用。假如,你想拥有多个独立的处理单元(independent processing units)(你可以为每一位客户创建一个独立的会话,如果你想所有流程在各客户之间独立完成);或者考虑到可扩展因素需要多个会话。刚开始,你可能不知从何下手。那先从最简单的方式上手:将你所有的流程定义放在一个知识库中,使用一个会话来执行所有的流程。

4.1. jBPM API

jBPM 将与用户交互的API和其具体实现类进行清晰的隔离。公开API(public API)所展示出来大多特性,我们相信“一般”用户 都可以放心使用,且可以在各个稳定的发行版之间交叉使用。当然,专家用户可以直接访问内部类,但他们必须清楚他们的所做所为,内部API在将来可能会改变。

综上所述,jBPM API 通常用于(1)创建一个包含有流程定义的知识库,(2)创建一个session,启动新的流程实例、退出流程、注册监听器等等。

4.1.1. Knowledge Base 知识库

首先,你可以使用jBPM API创建一个知识库。知识库必须包含session将要执行的所有流程定义。创建知识库,使用的是知识库构建器(knowledge builder)。构建器从各种资源加载流程定义(如从类路径或者从文件系统),然后由构建器创建一个全新的知识库。以下代码片断展示了如何创建由一个流程定义组成的知识库(使用类路径资源)。

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

kbuilder.add(ResourceFactory.newClassPathResource("MyProcess.bpmn"), ResourceType.BPMN2);

KnowledgeBase kbase = kbuilder.newKnowledgeBase();
一旦加载知识库,你就应该创建一个session与引擎交互。此session用于启动新的流程,发送信号给事件(译者:signal events,信号事件?)等。下面的代码片断展示了创建会话和创建知识库一样简单,同时如何通过ID启动一个流程。
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

ProcessInstance processInstance = ksession.startProcess("com.sample.MyProcess");

ProcessInstace接口定义了所有session与流程交互的方法。如下:
/**

     * Start a new process instance.  The process (definition) that should

     * be used is referenced by the given process id.

     *

     * @param processId  The id of the process that should be started

     * @return the ProcessInstance that represents the instance of the process that was started

     */

    ProcessInstance startProcess(String processId);


    /**

     * Start a new process instance.  The process (definition) that should

     * be used is referenced by the given process id.  Parameters can be passed

     * to the process instance (as name-value pairs), and these will be set

     * as variables of the process instance.

     *

     * @param processId  the id of the process that should be started

     * @param parameters  the process variables that should be set when starting the process instance

     * @return the ProcessInstance that represents the instance of the process that was started

     */

    ProcessInstance startProcess(String processId,

                                 Map<String, Object> parameters);


    /**

     * Signals the engine that an event has occurred. The type parameter defines

     * which type of event and the event parameter can contain additional information

     * related to the event.  All process instances that are listening to this type

     * of (external) event will be notified.  For performance reasons, this type of event

     * signaling should only be used if one process instance should be able to notify

     * other process instances. For internal event within one process instance, use the

     * signalEvent method that also include the processInstanceId of the process instance

     * in question.

     *

     * @param type the type of event

     * @param event the data associated with this event

     */

    void signalEvent(String type,

                     Object event);


    /**

     * Signals the process instance that an event has occurred. The type parameter defines

     * which type of event and the event parameter can contain additional information

     * related to the event.  All node instances inside the given process instance that

     * are listening to this type of (internal) event will be notified.  Note that the event

     * will only be processed inside the given process instance.  All other process instances

     * waiting for this type of event will not be notified.

     *

     * @param type the type of event

     * @param event the data associated with this event

     * @param processInstanceId the id of the process instance that should be signaled

     */

    void signalEvent(String type,

                     Object event,

                     long processInstanceId);


    /**

     * Returns a collection of currently active process instances.  Note that only process

     * instances that are currently loaded and active inside the engine will be returned.

     * When using persistence, it is likely not all running process instances will be loaded

     * as their state will be stored persistently.  It is recommended not to use this

     * method to collect information about the state of your process instances but to use

     * a history log for that purpose.

     *

     * @return a collection of process instances currently active in the session

     */

    Collection<ProcessInstance> getProcessInstances();


    /**

     * Returns the process instance with the given id.  Note that only active process instances

     * will be returned.  If a process instance has been completed already, this method will return

     * null.

     *

     * @param id the id of the process instance

     * @return the process instance with the given id or null if it cannot be found

     */

    ProcessInstance getProcessInstance(long processInstanceId);


    /**

     * Aborts the process instance with the given id.  If the process instance has been completed

     * (or aborted), or the process instance cannot be found, this method will throw an

     * IllegalArgumentException.

     *

     * @param id the id of the process instance

     */

    void abortProcessInstance(long processInstanceId);


    /**

     * Returns the WorkItemManager related to this session.  This can be used to

     * register new WorkItemHandlers or to complete (or abort) WorkItems.

     *

     * @return the WorkItemManager related to this session

     */

    WorkItemManager getWorkItemManager();


4.1.3. 事件 Events

session提供多种方法注册及移除监听器。ProcessEventListener类用于监听与流程有关的事件,比如启动或完成一个流程,进入或退出一个节点等。下面我们展示一些ProcessEventListener类不一样的方法。事件对象提供了对事件有关联的流程实例和节点实例的访问接口(译者:原文是这样的"An event object provides access to related information, like the process instance and node instance linked to the event.”)。你可以使用这个API注册你自己的监听器。

public interface ProcessEventListener {

  void beforeProcessStarted( ProcessStartedEvent event );

  void afterProcessStarted( ProcessStartedEvent event );

  void beforeProcessCompleted( ProcessCompletedEvent event );

  void afterProcessCompleted( ProcessCompletedEvent event );

  void beforeNodeTriggered( ProcessNodeTriggeredEvent event );

  void afterNodeTriggered( ProcessNodeTriggeredEvent event );

  void beforeNodeLeft( ProcessNodeLeftEvent event );

  void afterNodeLeft( ProcessNodeLeftEvent event );

  void beforeVariableChanged(ProcessVariableChangedEvent event);

  void afterVariableChanged(ProcessVariableChangedEvent event);

}

jBPM的外箱提供了一个监听器。它用于创建一个审计日志(audit log)(可输出在控制器里,也可以输出在文件系统中的文件)。审计日志记录下运行时发生的各种事件,所以,可以很容易的断定应用程序中发生了什么。需要注意的是,此日志只能用于调试目的。默认支持以下日志记录器实现:
1. 控制台日志记录器:将所有的事件打印在控制台中。
2. 文件日志记录器:将所有的事件以XML格式写入一个文件。IDE可以以树的形式展示程序执行过程中所发生的事件。
3. 单线程的文件日志记录器:因为只有当关闭记录器或者事件的数量达到记录器预定义的量时,文件日志记录器才可以将日志写入磁盘。调试中的流程在运行时,日志是不能被使用的。在调试流程时,单线程的文件日志记录器每隔指定的时间就会向文件写入日志,使得日志记录器可以实时呈现流程。

如下所示,KnowledgeRuntimeLoggerFactory 让你可以添加一个日志记录器到你的session中。当创建一个控制台日志记录器时,必须传一个knowledge session参数给它。文件记录器的创建需要一个日志文件名。单线程文件日志记录器的创建则需要间隔时间参数(以毫秒为单位),以确定多久保存一次日志。在应用程序结束时,你必须关闭日志记录器。

KnowledgeRuntimeLogger logger =   KnowledgeRuntimeLoggerFactory.newFileLogger( ksession, "test" );

// add invocations to the process engine here,

// e.g. ksession.startProcess(processId);

...

logger.close();



基于文件的日志记录器将会创建一个XML格式的文件。该文件包含所有运行时发生的事件。可以使用Eclipse打开它,在Drools Eclipse插件的Audit视图中,所有事件呈现成一棵树。发生在后的事件将作为之前事件的孩子。以下截图是一个简单的例子,Events that occur between the before and after event are shown as children of that event. The following screenshot shows a simple example, where a process is started, resulting in the activation of the Start node, an Action node and an End node, after which the process was completed.

4.2. 基于知识的API
你也许注意到了,jBPM所暴露出的API是一个知识API。意味jBPM不只是着点于流程,暗藏(potentially)着允许你加载其他类型的知识的可能。然而对只关心流程的用户产生的影响很小。意思是你使用的是知识基类(KnowledgeBase)和知识会话(KnowledgeSession)而非流程基类(ProcessBase )和流程会话(ProcessSession)。

然而,如果你打算将业务规则或者复杂事件处理作为你应用程序的一部分,知识基类API允许用户以完全相同的方式将各种不同的类型的资源,如流程和规则,加入到相同的知识库中。这使得那些知道如何使用Drools Expert(处理业务规则)或者Drools Fusion(事件处理)的人瞬间将这些不同类型的知识统一起来。



加载中
返回顶部
顶部