jbpm5.1介绍(3)
在您好的应用程序中使用一个新的流程
流程处理
(1)你需要建立一个知识库,其中包含过程定义
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource("MyProcess.bpmn2"), ResourceType.BPMN2 );
加入你的进程生成器(可以添加多个进程)后,您可以创建一个新的知识基础,这样的:
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
请注意,这将抛出一个异常,如果知识库包含错误(因为它不能正确地分析您的流程)。
(2)你需要创建一个会话,沟通与流程引擎和启动过程的启动过程。
启动过程:启动一个特定的进程,你会需要调用您的会话的startProcess方法,并传递您要启动的进程的ID。例如:
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); ksession.startProcess("com.sample.hello");
startProcess方法的参数是需要启动的进程ID。当定义一个过程,这需要作为一个过程的财产(例如在Eclipse的属性视图显示,当您单击过程中的背景画布)指定进程ID。
当您启动的过程中,你可以指定额外的参数,用来传递额外的输入数据的过程中,使用startProcess(弦乐进程ID,地图参数)方法。额外的参数是一个名称 - 值对的集合。这些参数将被复制到新创建的进程实例的顶层变量的过程,所以他们可以在你的进程余下的直接访问。
数据
虽然流程图上指定的过程控制流的重点,它通常也有必要的过程,从数据的角度看。在整个执行过程中,数据可以检索,存储,传递和使用。
对于运行时的数据,存储在执行过程中中,过程变量都可以使用。变量是一个名称和一个数据类型定义。这可能是一个基本数据类型,如布尔,INT,或String,或任何Object的子类。变量可以定义一个变量的范围内。顶层的范围是过程本身的变量的范围。 Subscopes可以定义使用一个子进程。子范围定义的变量只在该范围内的节点访问。
每当访问一个变量,这个进程将寻找合适的变量范围定义变量。变量作用域的嵌套是不允许的。节点总是会寻找其父容器中的一个变量。如果无法找到该变量,它会看,一个人的父容器,等等,直到达到流程实例本身。如果无法找到该变量,读访问产量空,写访问会产生错误消息,继续执行的过程。
变量可以用各种方式:
- 流程级别的变量,可以设置启动时所提供的参数映射到thestartProcess方法调用一个过程。这些参数将作为进程范围的变量。
- 脚本操作,只需直接使用在其脚本的本地参数变量的名称可以访问的变量。例如,如果程序定义了一个变量类型“org.jbpm.Person”的过程中,在这个过程中的脚本可以访问此直接: person.setAge(10);更改一个脚本中的变量的值可以通过知识背景下:kcontext.setVariable(variableName, value);
- 服务任务(可重复使用的子过程)可以通过向外界(或另一个进程实例)过程变量的值变量映射到一个传出参数。例如,服务任务的参数映射可以定义的过程变量x的值应被映射到一个任务参数y对前被调用服务。您还可以注入一个硬编码的参数字符串,使用#{表达式}的过程变量值。例如,可以定义一个人的任务的描述,您需要联络人#{person.getName()}(其中人是一个过程变量),这个表达式将取代人的实际名称服务时需要调用。同样的服务(或可重复使用的子进程)的结果也可以被复制使用结果映射到一个变量。
- 各种其他节点也可以访问数据。例如事件节点可以存储在变量中的事件关联的数据,等检查的更多信息,不同的节点类型的属性。
最后,流程和规则都进入到全局,即全局变量和知识会话中的数据。的全局在行动就像变量直接访问。全局需要定义作为这一进程的一部分,才可以使用。例如,按一下指定动作脚本在Eclipse行动的属性编辑器时,全局按钮您可以定义的全局。您还可以设置一个全球从外面使用ksession.setGlobal(名称,值),或从内部使用kcontext.getKnowledgeRuntime()的过程脚本的价值在setglobal(名称,值);
约束
约束可用于在不同的地点,在你的流程,例如在一个不同的网关。 jBPM支持两种类型的约束:
- 守则约束的布尔表达式,他们到达时直接评价。我们目前支持两种方言表达这些代码限制:Java和MVEL。 Java和MVEL代码的限制直接访问,并在这个过程中中定义的全局变量。下面是一个有效的Java代码的约束,人在这个过程中的一个变量的一个例子:return person.getAge()>20;一个类似的例子是一个有效MVEL代码约束:return person.age > 20;
- 规则约束等于正常的Drools的规则条件。他们使用了Drools规则语言语法表达可能是复杂的约束。这些规则可以像任何其他规则,是指在工作内存中的数据。他们还可以直接向全局。下面是一个有效的规则约束的例子:Person( age > 20 )
规则约束,没有直接访问内部的过程中定义的变量。不过,这是有可能加入流程实例工作记忆在你的规则约束和匹配过程实例内的规则约束,指当前进程的实例。我们已经添加了特殊的逻辑,以确保变量的类型WorkflowProcessInstance流程实例将只匹配当前进程的实例,而不是在工作内存中的其他进程实例。请注意,不过,你是负责自己插入到会话的过程实例,可能的话,更新它,例如,使用Java代码或在你的进程进入或退出或明确的行动。规则的约束下面的例子将一个人在变量“名称”的过程中存储的值相同的名称搜索:
processInstance : WorkflowProcessInstance() Person( name == ( processInstance.getVariable("name") ) ) # add more constraints here ...
动作角本
动作脚本可以使用不同的方式:
- 在脚本任务中
- 进入或者退出动作中
操作全局和过程和预定义变量kcontext的定义的变量的访问。此变量的类型org.drools.runtime.process.ProcessContext,可用于多个任务:
获取当前节点的实例(如适用)。节点的实例,如它的名称和类型的数据,可以查询。您还可以取消当前节点的实例。
NodeInstance node = kcontext.getNodeInstance(); String name = node.getNodeName();
获取当前进程的实例。可以查询流程实例数据(名称,ID,进程ID等),中止或暗示内部事件。
ProcessInstance proc = kcontext.getProcessInstance(); proc.signalEvent( type, eventObject );
获取或设置变量的值。
访问知识库中运行时,允许你不喜欢的东西开始一个进程,信号(外部)事件,插入数据,等
jBPM的目前支持两种方言,Java和MVEL。 Java的行动应该是有效的Java代码。 MVEL行动可以使用的业务脚本语言MVEL表达的行动。 MVEL接受任何有效的Java代码,但此外提供支持嵌套的参数访问(例如,person.name,而不是person.getName()),和许多其他的脚本改进。因此,MVEL表达式为商业用户更方便。例如,一个动作,打印出的人在“请求者”的过程变量的名称看起来像这样:
// Java dialect System.out.println( person.getName() ); // MVEL dialect System.out.println( person.name );
活动
在执行过程中,流程引擎可以确保所有相关的任务是根据工艺方案执行,请求执行的工作项目,并等待结果。然而,它也有可能这一进程应作出回应,不直接由流程引擎要求的事件。明确代表这些事件的过程中允许指定过程中应如何应对此类事件的过程作者。
事件有一个类型,可能与他们相关的数据。用户可以自由定义自己的事件类型及其相关的数据。
一个进程可以指定如何使用消息事件响应的事件。一个事件节点需要指定类型的事件节点感兴趣,它也可以定义一个变量的名字,这将收到与该事件相关的数据。这使得在这个过程中的后续节点访问事件数据,并根据该数据,采取适当的行动。
事件可能标志着一个在多种方式的过程正在运行的实例:
内部事件:任何一个进程内的行动(例如,行动节点的行动,或一些节点上进入或退出行动)信号的内部事件的发生,周围的流程实例,使用类似的代码以下内容:
kcontext.getProcessInstance().signalEvent(type, eventData);
外部事件:事件通知一个流程实例可以从外面用,如代码:
processInstance.signalEvent(type, eventData);
使用事件相关,而是直接通知一个流程实例的外部事件,它也可以让发动机自动确定流程实例可能会使用事件的相关性,这是基于事件类型的事件感兴趣。这样的事件发生时,一个流程实例包含事件节点听某种类型的外部事件通知。信号此类事件的流程引擎,写代码,如:
ksession.signalEvent(type, eventData);
事件也可以被用来启动一个进程。每当消息开始事件定义一个特定类型的事件触发,将会启动新的流程实例,每次事件的类型,信号流程引擎。
计时器
计时器等待一个预定义的时间,触发前,一次或多次。他们可以使用一段时间后触发一定的逻辑关系,或定期重复某些动作。
定时器节点设置一个延迟和一个时期。延迟指定的时间节点激活后等待触发定时器首次。这一时期定义随后触发激活之间的时间。期间,一个在单次触发定时器0的结果。
表达的形式应[#][#H] [#M] [#S] [#[MS]。这意味着,您可以指定天,小时,分钟,秒和multiseconds(这是默认的,如果你不指定任何)的数量。例如,表达“1H”将等待触发定时器(再次)一小时。
负责确保在适当的时候触发,定时器得到的定时服务。定时器也被取消,这意味着将不再被触发定时器。
定时器可用于在一个进程内的两个方面:
计时器事件可能会增加流动过程。其激活启动定时器,它触发时,一次或多次,它会激活定时器节点的继任者。这意味着,以积极的时期传出连接定时器触发多次。取消定时器节点也取消了相关的计时器,在这之后没有更多的触发会发生。
定时器可以与一个子进程,作为一个边界事件。但是,这是目前唯一可能直接在XML。我们将加入支持在新的BPMN2编辑器以图形方式指定。
更新流程
随着时间的推移,流程可能演变例如,因为这个过程本身需要加以改进,或由于不断变化的需求。其实,你真的不能更新的过程,你只能部署一个新版本的过程中,旧的过程将依然存在。这是因为现有的流程实例,可能还需要这一过程定义。因此,新的过程,应该有一个不同的ID,虽然名称可能是相同的,可以使用的版本参数表明,当一个进程更新(版本参数只是一个字符串,而不是进程的框架本身的验证,所以你可以选择自己的格式,用于指定小/大的更新等)。
每当一个更新过程,重要的是,以确定哪些应该发生到已经运行的进程实例。有不同的策略之一,可以考虑为每个运行实例:
步骤操作:正在运行的进程实例的收益为正常,因为它是定义流程实例启动时,下面的过程(定义)。因此,已经运行的实例会进行过程中,仿佛从来没有更新。新的实例可以开始使用更新的过程。
中止并重新启动已经运行的实例被中止。如果有必要,可以重新启动的过程实例,使用新的流程定义。
传输:过程实例迁移到新的流程定义,含义, - 一旦它被成功迁移 - 将继续执行的基础上更新的过程逻辑。
默认情况下,jBPM的使用进行的方法,这意味着可以部署同一进程的多个版本,但现有的流程实例将简单的启动流程实例时所使用的流程定义的基础上继续执行。总是可以被中止正在运行的进程实例,以及当然,在使用过程中的管理API。过程实例迁移是比较困难的,是在下面的段落解释。
流程实例的迁移
一个流程实例包含所有运行中的信息,需要继续执行一些在稍后的时间点。这包括所有链接到这个过程实例(如变量)的数据,而且在这个过程中图的当前状态。对于当前处于活动状态的每个节点,一个节点的实例是用来表示。这个节点的实例,也可以包含额外的状态链接到仅该特定节点的执行。有不同类型的节点实例,每个类型的节点之一。
一个流程实例只包含运行时的状态,并链接到一个特定的进程(间接使用ID引用)表示在执行这个流程实例(这明确的定义和运行时状态分离时,需要遵循的流程逻辑允许重用的跨越这个过程中,最大限度地减少运行时的状态为基础的所有流程实例)的定义。因此,更新一个正在运行的进程实例,所以它使用了新的进程逻辑,而不是旧到新的版本是一个简单的改变从旧到新的ID引用的进程ID的问题。
但是,这并没有考虑到流程实例的状态(变量实例和节点实例)以及可能需要迁移。仅扩展的过程和所有现有的等待状态保持的情况下,这是非常简单,流程实例的运行状态并不需要改变。然而,也有可能是一个更sofisticated的映射是必要的。例如,现有的等待状态时被删除,或分割成多个等待状态,等待在该国现有流程实例,不能简单地更新。或者引入一个新的进程变量时,该变量可能需要initiazed正确的,因此它可以在(更新)过程中的其余部分使用。
WorkflowProcessInstanceUpgrader可以使用工作流过程实例升级到一个新的流程实例。当然,您需要提供的流程实例和新的进程ID。默认情况下,jBPM将自动新节点具有相同的ID实例映射旧节点实例。但是你可以提供一个旧的(唯一的)节点ID映射到新的节点ID。惟一的节点ID的节点ID,其父母的节点ID(冒号inbetween)之前,允许唯一标识一个节点时使用复合节点(节点ID节点容器内只有独特。新的节点ID简直是在新的节点ID节点的容器(所以这里没有惟一的节点ID,只是新的节点ID)。下面的代码片段显示了一个简单的例子。
// create the session and start the process "com.sample.process" KnowledgeBuilder kbuilder = ... StatefulKnowledgeSession ksession = ... ProcessInstance processInstance = ksession.startProcess("com.sample.process"); // add a new version of the process "com.sample.process2" kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add(..., ResourceType.BPMN2); kbase.addKnowledgePackages(kbuilder.getKnowledgePackages()); // migrate process instance to new version Map<String, Long> mapping = new HashMap<String, Long>(); // top level node 2 is mapped to a new node with id 3 mapping.put("2", 3L); // node 2, which is part of composite node 5, is mapped to a new node with id 4 mapping.put("5.2", 4L); WorkflowProcessInstanceUpgrader.upgradeProcessInstance( ksession, processInstance.getId(), "com.sample.process2", mapping);
如果这种映射仍然不足,你仍然可以描述自己的自定义映射器,针对具体情况。请务必先断开流程实例,相应地改变状态,然后重新连接的过程实例,类似如何WorkflowProcessinstanceUpgrader它。
业务流程模型和符号(BPMN)2.0规范
BPMN的主要目标是提供一个符号,是所有业务用户容易理解的, 从创建进程的初稿,业务分析师,技术开发 负责实施的技术,将执行这些进程,并最终到 商界人士将管理和监视这些进程。“
业务流程模型和符号(BPMN)2.0规范,不仅定义了一个标准,就如何以图形方式表示业务流程(如BPMN1.x的)是OMG规范,但现在还包括为执行定义的元素语义,和XML格式(股)如何存储过程定义。
jBPM5允许执行使用的BPMN 2.0的XML格式定义的流程。这意味着,您可以使用所有不同的jBPM5模具模型,执行,管理和监控您的业务流程,指定可执行的业务流程中使用的BPMN2.0格式。事实上,完整的BPMN 2.0规范还包括如何表示像编排和和协作的事情的细节。然而,jBPM项目的重点部分,可用于指定可执行流程的规范。
BPMN中的可执行文件的进程,包括不同类型的节点被连接到对方使用顺序流。 BPMN 2.0规范定义了三种主要类型的节点:
事件:它们用于模型中的特定事件的发生。这可能是一个开始事件(即用来指示的过程中开始),结束事件(定义过程结束,或该子流)和中间事件(指示的执行过程中可能出现的事件过程)。
活动:这些定义,需要在执行过程中执行不同的动作。存在不同类型的任务,对活动的类型取决于您尝试模型(如人工的任务,服务任务等)和actvities也可以嵌套(使用不同类型的子进程)。
网关:可以被用来定义多个路径的过程中。根据网关类型,这些可能表明并行执行,选择等
jBPM5没有实现在BPMN 2.0规范定义的所有元素和属性。然而,我们支持一个显著的子集,包括可执行的流程内,可使用的最常见的节点类型。这包括几乎所有元素,并在BPMN 2.0规范的“共同的可执行文件”子类与一些额外的元素和属性,我们相信扩展,定义的属性,以及在这方面的宝贵。下面可以找到全套支持的元素和属性,但它包含了像元素:
流程对象包括
- Flow objects
- Events
- Start Event (None, Conditional, Signal, Message, Timer)
- End Event (None, Terminate, Error, Escalation, Signal, Message, Compensation)
- Intermediate Catch Event (Signal, Timer, Conditional, Message)
- Intermediate Throw Event (None, Signal, Escalation, Message, Compensation)
- Non-interrupting Boundary Event (Escalation, Timer)
- Interrupting Boundary Event (Escalation, Error, Timer, Compensation)
- Activities
- Script Task
- Task
- Service Task
- User Task
- Business Rule Task
- Manual Task
- Send Task
- Receive Task
- Reusable Sub-Process (Call Activity)
- Embedded Sub-Process
- Ad-Hoc Sub-Process
- Data-Object
- Gateways
- Diverging
- Exclusive
- Inclusive
- Parallel
- Event-Based
- Converging
- Exclusive
- Parallel
- Diverging
- Lanes
- Events
- Data
- Java type language
- Process properties
- Embedded Sub-Process properties
- Activity properties
- Connecting objects
- Sequence flow
例如,考虑下面的“你好世界”BPMN 2.0的过程中,它什么也不做,写一个“Hello World”的说法时,过程开始。
这个过程的可执行版本使用BPMN 2.0的XML表示会看起来像这样:
<?xml version="1.0" encoding="UTF-8"?> <definitions id="Definition" targetNamespace="http://www.example.org/MinimalExample" typeLanguage="http://www.java.com/javaTypes" expressionLanguage="http://www.mvel.org/2.0" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.jboss.org/drools"> <process processType="Private" isExecutable="true" id="com.sample.HelloWorld" name="Hello World" > <!-- nodes --> <startEvent id="_1" name="StartProcess" /> <scriptTask id="_2" name="Hello" > <script>System.out.println("Hello World");</script> </scriptTask> <endEvent id="_3" name="EndProcess" > <terminateEventDefinition/> </endEvent> <!-- connections --> <sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" /> <sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" /> </process> <bpmndi:BPMNDiagram> <bpmndi:BPMNPlane bpmnElement="Minimal" > <bpmndi:BPMNShape bpmnElement="_1" > <dc:Bounds x="15" y="91" width="48" height="48" /> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_2" > <dc:Bounds x="95" y="88" width="83" height="48" /> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_3" > <dc:Bounds x="258" y="86" width="48" height="48" /> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="_1-_2" > <di:waypoint x="39" y="115" /> <di:waypoint x="75" y="46" /> <di:waypoint x="136" y="112" /> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_2-_3" > <di:waypoint x="136" y="112" /> <di:waypoint x="240" y="240" /> <di:waypoint x="282" y="110" /> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
要创建自己的过程,使用BPMN 2.0的格式,你可以
创建一个新的流文件,使用Drools Eclipse插件的向导,在向导的最后一页,确保你选择的Drools5.1的代码兼容性。使用BPMN 2.0的XML格式,这将创建一个新的进程。但是请注意,这是不完全的BPMN 2.0编辑器,因为它仍然使用不同属性的名称等,但它确实保存过程中使用有效的BPMN2.0的语法。另外请注意,编辑器不支持所有节点类型和已在执行引擎支持的属性。
设计师是一个开源的基于Web的编辑器,支持BPMN2.0格式。我们已经嵌入到Guvnor BPMN 2.0的流程可视化和编辑。你可以使用Designer(独立或集成)创建/编辑BPMN 2.0流程,然后出口到BPMN 2.0的格式,或将其保存到Guvnor,使他们能够执行。
正在创建一个新的BPMN2的Eclipse插件,支持完整的BPMN2规范。这是目前仍在开发中,只支持数量有限的结构和属性,但已经可以用来创建简单的BPMN2流程。要创建一个新的BPMN2的这个编辑器的文件,使用向导(下例子)创建一个新的BPMN2的文件,这将产生一个。BPMN2文件和一个。珠三角文件包含图形信息。双击。珠三角文件中使用的图形化编辑器编辑该文件。
通过直接写入XML,您可以随时手动创建BPMN 2.0的流程文件。您可以对BPMN 2.0的XSD验证你的流程的语法,或在Eclipse插件的使用验证器来检查你的模型的语法和完整性。
下面的代码片段显示了你如何加载到你的知识库一个BPMN2的过程......
private static KnowledgeBase createKnowledgeBase() throws Exception { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add(ResourceFactory.newClassPathResource("sample.bpmn2"), ResourceType.BPMN2); return kbuilder.newKnowledgeBase(); }
... ...如何执行此过程中......
KnowledgeBase kbase = createKnowledgeBase(); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); ksession.startProcess("com.sample.HelloWorld");
持久化和转换
jBPM的持久存储允许某些信息,即流程的运行时的状态,历史信息等
1)运行时状态
每当启动一个过程,一个过程实例被创建,它代表的过程,在这种特定情况下执行。例如,在执行的过程中,指定如何处理销售订单时,一个流程实例创建要求每个销售。流程实例代表当前的执行状态,在这种特定情况下,并包含所有相关信息,流程实例。请注意,它仅包含最小的运行状态,需要继续这一进程的实例在执行一段时间后,但它不包括对这一进程的实例历史的信息,如果该信息不再需要在流程实例。
执行过程中的运行状态,可以持久的,例如,在数据库中。这使得恢复意外故障的情况下,所有正在运行的进程的执行状态,或者暂时从内存中删除正在运行的实例,并在一段时间后恢复它们。 jBPM的允许您插入不同的持久性策略。默认情况下,如果你不配置的流程引擎,否则,流程实例没有持久性。
二进制持久性
jBPM提供了一个二进制的持久性机制,允许您保存为二进制数据集的一个流程实例的状态。通过这种方式,所有正在运行的进程实例的状态总是可以被储存在一个持久的位置。请注意,这些二进制数据集通常都比较小,因为它们只包含最小的流程实例的执行状态。对于一个简单的过程实例,这通常包含一个或几个节点的实例,即任何节点当前正在执行,并且,可能的话,一些变量的值。
安全点
一个流程实例的状态存储在流程引擎执行所谓的“安全点”。每当一个流程实例执行后启动或从一个等待状态的延续,发引擎的收益可以执行,直到没有更多的行动。在这一点上,引擎已达到未来的安全状态,并坚持存储过程实例的状态和所有其他的进程有可能受到影响的实例。
配置持久性
默认情况下,流程引擎不保存运行时的数据持续。然而,它可以通过非常简单的配置做到这一点,通过添加一个配置文件和必要的依赖。基于Java持久性API(JPA)的持久性本身,因此可以与几个持久性机制。我们使用Hibernate在默认有情况下。用H2数据库来存储数据,但你可以选择你自己的选择。
首先,你需要添加必要的依存关系到你的classpath。如果你使用Eclipse IDE,你可以通过添加JAR文件到你的jBPM运行时目录,或通过手动添加这些依赖关系到您的项目。首先,你需要的JAR文件与jBPM持久化jpa.jar,包含用于保存运行时的状态,必要时的代码。接下来,您还需要其他各种依赖关系,具体取决于您使用的持久性解决方案和数据库。与Hibernate作为JPA持久性提供程序,H2数据库和JTA的事务管理Bitronix默认组合,下面的列表是需要额外的依赖:
- jbpm-persistence-jpa (org.jbpm)
- drools-persistence-jpa (org.drools)
- persistence-api (javax.persistence)
- hibernate-entitymanager (org.hibernate)
- hibernate-annotations (org.hibernate)
- hibernate-commons-annotations (org.hibernate)
- hibernate-core (org.hibernate)
- dom4j (dom4j)
- jta (javax.transaction)
- btm (org.codehaus.btm)
- javassist (javassist)
- slf4j-api (org.slf4j)
- slf4j-jdk14 (org.slf4j)
- h2 (com.h2database)
- commons-collections (commons-collections)
接下来,您需要配置jBPM引擎在必要时保存引擎的状态。要做到这一点最简单的方法是使用JPAKnowledgeService创建您的知识会话,基于知识基础,知识的会话配置(如有必要)和环境。环境需要包含您的实体管理器工厂的引用。例如:
// create the entity manager factory and register it in the environment EntityManagerFactory emf = Persistence.createEntityManagerFactory( "org.jbpm.persistence.jpa" ); Environment env = KnowledgeBaseFactory.newEnvironment(); env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf ); // create a new knowledge session that uses JPA to store the runtime state StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); int sessionId = ksession.getId(); // invoke methods on your method here ksession.startProcess( "MyProcess" ); ksession.dispose();
您还可以YSE的JPAKnowledgeService重新创建基于一个特定的会话ID的会话:
// recreate the session from database using the sessionId ksession = JPAKnowledgeService.loadStatefulKnowledgeSession( sessionId, kbase, null, env );
请注意,我们只保存最小的状态,是需要继续在以后的某个点的执行过程实例。这意味着,例如,它不包含已经执行的节点的信息,如果该信息不再是相关的,或已完成或中止从数据库中删除该进程的实例。如果你想搜索历史相关的信息,你应该使用的历史记录,后面会解释。
你需要添加一个持久性配置到你的classpath配置JPA的使用Hibernate和H2数据库(或您的偏好),名为persistence.xml的META - INF目录中,如下所示。对于如何改变自己的配置的更多细节,我们指的JPA和Hibernate文档了解更多信息。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persistence version="1.0" xsi:schemaLocation= "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="org.jbpm.persistence.jpa"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/processInstanceDS</jta-data-source> <class>org.drools.persistence.info.SessionInfo</class> <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.max_fetch_depth" value="3"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup"/> </properties> </persistence-unit> </persistence>
这个配置文件是指所谓的“JDBC / processInstanceDS”数据源。下面的Java代码片段可以用来设置该数据源,在这里我们使用的是基于文件的H2数据库。
PoolingDataSource ds = new PoolingDataSource(); ds.setUniqueName("jdbc/testDS1"); ds.setClassName("org.h2.jdbcx.JdbcDataSource"); ds.setMaxPoolSize(3); ds.setAllowLocalTransactions(true); ds.getDriverProperties().put("user", "sa"); ds.getDriverProperties().put("password", "sasa"); ds.getDriverProperties().put("URL", "jdbc:h2:file:/NotBackedUp/data/process-instance-db"); ds.init();
如果你部署到应用服务器,通常可以deploy目录中的配置文件,例如,创建一个数据源:
<?xml version="1.0" encoding="UTF-8"?> <datasources> <local-tx-datasource> <jndi-name>jdbc/testDS1</jndi-name> <connection-url>jdbc:h2:file:/NotBackedUp/data/process-instance-db</connection-url> <driver-class>org.h2.jdbcx.JdbcDataSource</driver-class> <user-name>sa</user-name> <password>sasa</password> </local-tx-datasource> </datasources>
2)转换
只要你不提供您的应用程序内的事务边界,发动机对发动机会自动执行一个单独的事务中的每个方法调用。如果这种行为是可以接受的的,你不需要做别的。你可以,但是,也可以指定自己的事务边界。例如,这可以让你组合成一个事务的多个命令。
您需要注册后在环境中使用用户定义的事务之前,事务管理器。下面的代码示例使用的Bitronix事务管理。接下来,我们使用Java事务API(JTA),指定事务边界,如下图所示:
// create the entity manager factory and register it in the environment EntityManagerFactory emf = Persistence.createEntityManagerFactory( "org.jbpm.persistence.jpa" ); Environment env = KnowledgeBaseFactory.newEnvironment(); env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf ); env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() ); // create a new knowledge session that uses JPA to store the runtime state StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); // start the transaction UserTransaction ut = (UserTransaction) new InitialContext().lookup( "java:comp/UserTransaction" ); ut.begin(); // perform multiple commands inside one transaction ksession.insert( new Person( "John Doe" ) ); ksession.startProcess( "MyProcess" ); // commit the transaction ut.commit();
流程定义
流程定义文件通常被写在一个XML格式。这些文件可以很容易地存储在文件系统在开发过程中。但是,只要你想使你的知识在生产中的一个或多个引擎访问,我们建议使用(逻辑)你的知识集中在一个或多个知识库Guvnor是Drools的一个分项目,提供这一点。它由一个仓库,用于存储不同类型的知识,不仅流程定义,但也规则,对象模型等,它允许使用WebDAV的知识或运用知识代理,当创建一个自动下载信息Guvnor便于检索的知识基础,提供了一个Web应用程序,允许业务用户可以查看和更新知识信息库中的信息。如何做到这一点的更多信息,检索的Drools Guvnor文档。
历史记录
在许多情况下是非常有用(如果没有必要的话)的存储流程实例的执行信息,使这一信息可用于事后,例如,为了验证一个特定的流程实例执行过什么行动,或监测和分析一个特定的进程效率。在运行时数据库中存储的历史信息通常不是一个好主意,因为这将导致在不断增长的运行数据,监测和分析,查询可能会影响您的运行时引擎的性能。这就是为什么历史的流程实例的执行信息是分开存储。
这执行信息的历史记录是创建基于流程引擎在执行过程中生成的事件。 jBPM运行时引擎提供了一个通用的机制,听取各种不同的事件。必要的信息可以很容易地从这些事件中提取中,持久化,例如在数据库中,。过滤器可用于存储你找到相关的信息。
存储在数据库中处理事件
jBPM的BAM模块包含一个事件监听器进程相关的信息存储在一个数据库,直接使用JPA或Hibernate。该数据库包含了两个表,一个流程实例信息和一个节点实例的信息(见下图):
1.ProcessInstanceLog:这列出的过程实例ID,进程(定义)ID,开始日期和(如适用)的所有流程实例的结束日期。
2.NodeInstanceLog:此表包含哪些节点实际上每个流程实例内执行的更详细的信息。每当一个节点实例进入进来的连接,或通过其传出连接退出,这些信息是存储在此表中中。对于这一点,它存储过程实例ID和它正在执行中的流程实例的进程ID和节点实例ID和相应的节点ID的节点实例中的问题(在这个过程中定义)。最后,事件的类型(0=输入,1 =退出)和事件的日期,以及存储。
日志数据库在这样的历史进程信息,您需要注册您的会话(或工作记忆)的记录,像这样的:
StatefulKnowledgeSession ksession = ...; JPAWorkingMemoryDbLogger logger = new JPAWorkingMemoryDbLogger(ksession); // invoke methods one your session here logger.dispose();
请注意,此记录是像其他任何审计记录器,这意味着你可以调用的方法addFilter,以确保只有相关信息存储在数据库中添加一个或多个过滤器。只有所有过滤器所接受的的信息会出现在数据库中。它不再需要时,您应将该记录器。
要指定应存储信息的数据库,修改的文件persistence.xml文件,包括审计日志类以及(ProcessInstanceLog,NodeInstanceLog和VariableInstanceLog),如下所示。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persistence version="1.0" xsi:schemaLocation= "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="org.jbpm.persistence.jpa"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/processInstanceDS</jta-data-source> <class>org.drools.persistence.info.SessionInfo</class> <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <class>org.jbpm.process.audit.ProcessInstanceLog</class> <class>org.jbpm.process.audit.NodeInstanceLog</class> <class>org.jbpm.process.audit.VariableInstanceLog</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.max_fetch_depth" value="3"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup"/> </properties> </persistence-unit> </persistence>
所有这些信息可以方便地查询和使用,在很多不同的使用情况,从创建一个特定的流程实例分析特定进程的所有实例的性能的历史记录。
只应考虑该审计日志的默认实现。我们不知道你需要什么样的信息存储进行分析之后,由于性能原因,建议只存储有关数据。根据你的用例,你可能会定义您自己的数据模型,用于存储你需要的信息,并在使用过程中的事件监听器来提取这些信息。