jboss jbpm_使用JBoss ESB和JBPM实施VMS解决方案

jboss jbpm

垂直市场解决方案(VMS)是NAVTEQ内的组织,为客户提供定制解决方案,包括移动门户和连接的导航系统。 这些解决方案结合了NAVTEQ提供的服务和第三方服务,以客户特定的形式(包括Web服务,WAP,门户等)提供复合服务和内容。

VMS在应对众多销售机会以及预测未来客户需求方面所面临的挑战要求开发可组合的服务,这些服务可快速轻松地集成到完整的客户解决方案中。 支持服务集成的中间件对于交付此类系统至关重要。

在本文中,我将讨论如何使用JBoss中间件平台,特别是JBoss ESB和jBPM(JBoss业务流程管理)来构建这样的系统。

整体解决方案

在深入研究JBoss中间件产品的细节之前,我将在这里快速描述我们构建VMS解决方案的基本方法。

当前,NAVTEQ提供了此类解决方案所需的所有功能,包括功能强大的基于位置的服务(如地理编码和路由),与交通有关的服务(如有关事故的信息,交通拥堵因子计算和给定路线的交通警报),以及一般电子商务功能,包括购买,授权和权利管理。

将这些服务直接提供给消费者的问题有很多:

  • 每种服务都有特定的用途,而NAVTEQ客户则需要复合服务。 例如,客户可能需要围绕其路线的交通和事件警报。 这可以通过几个步骤来实现-对起点,终点和路口点进行地理编码,计算路线,获取路线周围的事件信息,获取路线的路况信息。 这一系列步骤构成了应根据用户要求创建的新的复合服务。
  • 现有功能正在有机增长,因此所有这些服务都使用不同的数据模型/定义,这使它们的使用和编排变得复杂。
  • 不同的客户可能需要通过不同的机制交付内容/服务。 一些人可能希望能够使用SOAP或REST直接访问服务,一些人可能希望将html / javascript片段传递到其网页/门户,一些人可能需要WAP服务接口。
  • 现有的实现具有自己的安全性,用户管理,监视和管理体系结构/实现。

结果,对于我们的实现,我们决定使用如图1所示的总体架构。

图1整体解决方案架构

VMS平台位于此体系结构的中心,通过协调现有的后端功能来实现特定客户所需的服务。 该平台包括三个主要层:

  • 后端适配器-负责访问现有的后端(或/和第三方 )功能并且使执行结果(在标准域模型的形式)转换成一个平台的层。
  • 服务实施层-负责将现有服务(可通过后端适配器访问)编排为客户所需的服务。 此外,可以在此层中实现一些当前不存在的自定义功能。
  • 消费者适配器–负责通过不同协议/传输向不同类型的客户端交付服务执行结果的层。

在本文的其余部分,我将讨论如何使用JBoss中间件平台实现该体系结构。

JBoss ESB

JBoss ESB是基于RosettaNet ESB的企业服务总线的开源实现,并支持服务的创建,部署和集成。

在架构上,Jboss ESB中的所有内容都是服务。 这些服务不是Web服务,而是ESB服务,可以通过各种传输方式公开。 ESB服务是单一方法(doWork)服务,可以使用以下界面(由所有服务共享)来描述:

消息输出= service.doWork(消息输入)

ESB消息在某种程度上模仿SOAP消息,并且由几部分组成,包括标题,正文,错误,附件等。每个部分都可以包含可按名称访问的可序列化Java对象的集合(映射)。 这意味着JBoss ESB消息不是强类型的,实现对消息的访问(类型转换)时应格外小心。

服务定义应采用以下格式:

  • 服务类别/名称 – Jboss ESB正在维护服务的内部注册(服务在部署期间自行注册)。 JBoss ESB在内部决定访问服务的最佳机制。
  • 输入消息的组成部分 -包括其名称(在传入消息的正文中)和类型。
  • 输出消息的组成部分 -包括其名称(在传出消息的正文中)和类型。

与使用一组拦截器构建的传统ESB实现不同,它允许在服务调用管道中注入额外的处理,JBoss ESB将服务作为显式管道实现,可以包含任意动作集(图2),每个动作都实现(可能是部分)服务业务功能或基础结构支持,例如将服务消息存储在消息存储中。

图2 JBoss ESB服务

与传统的基于拦截器的技术可以更好地将“业务”(服务实现)和基础结构(拦截器)关注点区分开来,JBoss ESB将两者混为一谈。 但是,这并非没有好处,因为在单个服务管道中包含所有操作可以简化对整体服务处理的理解。

JBoss ESB中的服务操作是一个Java类,实现了org.jboss.soa.esb.actions.ActionLifecycle接口。 服务实现者通常在一组动作中分解服务功能,然后实现每个动作。 这种服务实现的组织方式为JBoss ESB开发人员提供了两种重用级别:服务本身和可以在多个服务之间重用的操作。 JBoss还提供了丰富的可重用操作库。 该库包括以下类型的操作1

  • 变压器与转换器
  • JBPM支持
  • 脚本编写
  • 路由
  • Web服务支持
  • 杂项

服务请求可以通过多种运输方式交付。 服务定义包括对该服务侦听的传输/端点集的引用(此端点对于给定服务必须是唯一的)。 服务定义还允许通过(在传输的基础上)指定专用于处理服务请求的线程数来配置服务吞吐量。

在jboss-esb.xml文件中指定了服务动作调用的设置和顺序以及服务正在侦听的端点。 这允许基于一组动作(由JBoss提供或特定于给定公司或服务)配置给定服务。 对动作的外部XML配置的这种支持进一步提高了动作重用的可能性。

JBoss ESB中的服务调用

如前所述,JBoss ESB中的所有内容都是一项服务,其中“异步2调用”是默认模式。 同步调用也受支持,并通过使用相关性来实现。 ESB服务的同步调用与异步调用可以通过两种方式控制:

  • 服务实现者可以使用消息交换模式(MEP)参数定义服务行为。 默认的MEP是“请求-响应”,这意味着服务能够返回响应。 如果MEP设置为单向,则服务不能也不会返回答复
  • 服务使用者可以定义他是否需要服务的答复。 如果被请求,具有请求-响应MEP的服务将返回响应3

为了简化服务调用,Jboss ESB提供了org.jboss.soa.esb.client.ServiceInvoker类,该类基于类别/服务名称支持非常简单的服务调用接口。

JBoss ESB中的本地服务调用

除了远程传输,JBoss还提供了非常快速的本地(在同一JVM内)调用机制,该机制通过内存中队列提供服务调用。 如果将org.jboss.soa.esb.client.ServiceInvoker类用于服务调用,并且在本地部署了支持本地调用的服务,则始终选择内存中传输以优化性能。

Web服务支持

如今,当人们谈论ESB时,他们通常会强调Web服务处理。 从技术上讲,JBoss ESB具有许多基于Web服务的组件,用于公开和调用Web Service端点(即,在总线上和从总线上的SOAP):

SOAP处理器 action支持通过任何JBossESB托管的侦听器调用JBossWS托管的Web Service端点。 这意味着ESB可用于公开任何ESB服务的Web服务端点。 此实现基于精简的Service Wrapper Web服务(例如JSR 181 4实现),该服务将对目标Service的调用进行包装。 这也意味着这些服务可以在ESB支持的任何传输通道(http,ftp,jms等)上调用。 SOAP处理器被配置为指向Web服务端点(使用JAXWS注释注释的Java类),该端点进行SOAP请求的实际处理。

SOAPClient 操作使用WISE 5客户端服务来生成JAXWS客户端类并调用目标服务。 它使用Web Service WSDL的URL动态生成JAXWS客户端以调用Web服务。

在我们的实现中,我们发现使用此支持相当麻烦,因此采用了以下策略:

  • 为了使用Web服务,我们从WSDL生成了可供我们使用的Web服务客户端(轴1,轴2和/或JBoss WS可以用于此操作)
  • 为了公开ESB服务,我们使用了JBoss WS(用于SOAP)和RestEasy(用于REST)来公开org.jboss.soa.esb.client.ServiceInvoker并调用所需的服务。 这种方法(在体系结构上)等效于SOAPProcessor操作的用法,但更通用一些,从而允许将服务功能公开为SOAP,REST或任何其他所需的接口。

JBoss ESB工具

服务侦听器和服务执行管道的配置是使用XML完成的。 XML配置包含在3个文件中,这是ESB服务6所必需的:

  • 文件jbm-queue-service.xml包含与服务7使用的每个传输(通常是队列)相关联的MBean的定义。
  • 文件deployment.xml包含服务依赖的所有传输的列表。 服务(ESB)部署程序使用此文件的内容来验证是否满足所有依赖关系。
  • 文件jboss-esb.xml包含所有侦听器和服务管道的定义。

虽然必须直接使用XML创建文件jbm-queue-service.xml和deployment.xml,但JBoss提供了简化ESB项目8的创建,部署和维护的工具。 图3展示了jboss-esb.xml编辑器的快照。

图3 JBoss ESB工具

该工具提供了图形支持,用于添加和配置侦听器,服务和单个操作(包括操作参数)。

使用Smooks进行数据转换

最重要的服务操作之一是数据转换。 JBoss ESB利用Smooks 9来实现此功能。 Smooks的基本原理是获取某种数据源并从中生成事件流。 然后,将访问者模式逻辑应用于此流,以产生不同类型的结果。 10支持许多不同的数据源和结果类型,这意味着支持许多不同的转换类型,包括(但不限于):

  • XML到XML
  • XML到Java
  • Java到XML
  • Java到Java
  • EDI转换为XML
  • EDI转换为Java
  • Java到EDI
  • CSV到XML
  • CSV到...

为了简化Smooks的使用,JBoss ESB提供了一个专门的动作< 11 ,可以将其配置为调用基于Smooks的转换作为服务管道的一部分。

为什么抽烟?
从技术上讲,可以直接在Java代码中实现的转换,那么为什么要使用Smooks? (请记住:Smooks是我们必须编写的XML配置,它通常比普通的Java实现慢12点 ……)

使用Smooks进行数据转换具有以下优点:

  • 与Java实现不同,Smooks不需要任何if-then逻辑。 已为源的所有元素定义了映射,如果源中不存在某个元素,则不会产生该事件,并且不会发生映射。
  • Smooks的结构自然会导致映射的组件化。
  • 使用Smook可以将转换定义外部化,从而改善了服务的整体维护。
  • JBoss / Smooks为Smooks工具提供了图形编辑器,用于设计转换

烟雾工具

JBoss ESB工具提供了一个图形编辑器,可以直观地定义Smooks转换。

图4 Smooks图形编辑器

创建转换后,Smooks的执行报告 (图5)允许直观地查看转换期间已执行的步骤顺序。 此直观检查可以大大简化Smooks转换的调试。

图5抽烟执行报告

常见的Smooks转换设计错误

在设计Smooks转换时,请务必记住处理过程不是上下文敏感的。 这意味着,例如,如果您有一个XML文档:

<a>
  <b>

	<c>12345</c>
  </b>
  <d>

	<c>12345</c>
  </d>
</a>

您的转换使用“ c”作为选择器; 它会被调用两次-一次在“ b”内部针对“ c”,另一次在“ d”内部针对,即使您在使用选择器“ b”的转换内部使用了此选择器。

为避免这些问题,请始终使用在源文档中全局唯一的选择器。

JBPM

JBoss jBPM是一种灵活,可扩展的过程语言框架13 。 jPDL是一种在该通用框架之上构建的过程语言。 它是一种流程语言,可以根据任务,异步通信的等待状态,计时器,自动操作和其他组件以图形方式表示业务流程。

jPDL具有最小的依赖性,并且可以像使用Java库一样容易使用。 此外,通过将其部署在J2EE集群应用程序服务器上,它还可以用于对吞吐量至关重要的环境中。 它可以配置有任何数据库,也可以部署在任何应用程序服务器上。

与BPEL紧密耦合到Web服务和Web服务调用(在BPEL中,每个活动都必须作为Web服务14实施 )不同,JBPM更多地是组件框架15 ,它允许直接调用Java处理程序(类似于ESB服务执行管道)

我已经有一个服务执行管道,为什么我需要其他服务编排机制?

服务管道和服务流程之间似乎有很多重叠。 简而言之,服务管道是动作的顺序编排。 它不能很好地支持,但通常是编排需求,包括–决策,条件转换和并行执行。 尽管从技术上讲,您可以在管道定义中做很多事情,但这并不总是那么容易。 我们倾向于使用服务管道来整合基本业务功能和其他基础架构支持,包括数据转换,执行监视等,并使用jBPM来协调这些服务。

此选择的其他考虑因素可能是部署要求。 如果在很多情况下都使用相同的操作,可能有必要将其分离到单独的服务中,以便仅将其部署一次并使用jBPM进行编排。

JPDL定义的主要结构包括节点和执行上下文。 JPDL定义以下类型的节点:

  • 启动节点–流程开始
  • 任务–人类活动
  • 状态-等待状态
  • 节点–自定义代码的执行
  • 决策–基于过程变量的决策
  • Fork –沿多个路径拆分执行
  • 联接–组合多个执行路径
  • 过渡–节点之间的链接
  • SuperState –多个节点的聚合
  • 终端节点–流程完成

执行上下文在某种程度上类似于HTTP会话,并且包含一组命名对象–与先前定义的ESB消息正文类似。 任何节点都可以访问执行上下文的内容以及上下文中包含的读/写变量。 执行状态保留在数据库中-JPDL进程处于等待状态时,其上下文(上下文变量)存储在数据库中; 当恢复该过程时,将从数据库中合并上下文变量,并重新创建上下文。

JPDL流程的主要力量(在服务编排的情况下)是Node。 一个典型的Node执行一个动作处理程序-一个实现org.jbpm.graph.def.ActionHandler接口的类。 与服务动作处理程序类似,节点动作处理程序是可配置的,尽管它们使用不同的配置方法。 可以通过流程定义来配置在动作处理程序实现类中定义的任何公共/私有变量。

异步执行

节点类型的节点可以配置为异步执行。 请注意,JPDL中的异步执行当前不是作为线程实现的,而是作为排队实现的。 如果异步执行节点执行,则进程的当前状态存储在数据库中。 这些存储的实例可由org.jbpm.job.executor.JobExecutor类拾取以继续。 运行此类的标准可配置机制是org.jbpm.job.executor.JobExecutorServlet servlet,可以将其配置为在单个WAR中运行。 我们选择在实现中不使用此机制。 我们通过调用JPDL的ESB服务来实现异步执行(有关详情,请参见下文)

决策节点是另一种支持自定义实现的节点。 该节点的功能由实现org.jbpm.graph.node.DecisionHandler接口的类实现。 实施节点功能时,可以与操作处理程序相同的方式配置决策处理程序。

JPDL中的并行执行是使用Fork / Join节点实现的。 连接Fork和Join节点的所有路径将并行实现。

叉/联接执行

.Fork的JPDL实现不是线程实现。 这意味着Fork实现不会为离开Fork节点的所有转换创建线程。 它为每个转换创建令牌。 因为进程执行是单线程的,所以所有这些令牌将按顺序执行。 实现Fork / Join并行执行的方法之一是通过从JPDL调用ESB服务(有关详细信息,请参见下文)

对服务的支持之一是在服务编排中广泛使用并且在JPDL中缺少的一件事。 使用“决策”节点评估循环变量可以轻松实现顺序循环。 并行循环是一个更复杂(但在服务编排中很常见)的方案-带有运行时计算过渡路径数量的Fork / Join。 JPDL中没有对此模式的专门支持,但是创建两个自定义处理程序来实现此功能非常容易(附录中的清单1,清单2)。

这些处理程序的实现基于JPDL Fork / Join实现。 启动处理程序创建多个(由名称为LoopCount的变量控制)令牌,然后启动所有令牌。 结束处理程序等待,直到所有子标记都完成,然后过渡到下一个节点。

异常处理

流程执行可能会遇到异常。 JPDL允许将异常处理程序与每个流程节点关联。 异常处理程序是一种动作处理程序,当节点执行期间发生异常时将调用该异常处理程序。 附录中提供了一个简单的异常处理程序的示例。 此异常处理程序打印异常信息,然后转换到目标变量中指定的节点。

流程部署

JPDL流程定义不是作为JBoss应用程序部署,而是部署在流程数据库中。

JBPM / ESB集成

JBoss ESB和JBPM都是非常强大的软件平台,但是通过ESB / JBPM集成,它们的功能会大大增强16

ESB / JBPM集成有两种类型:

  • 将业务流程作为服务公开
  • 从业务流程中调用服务。

JBoss / JBPM集成提供了专门的动作处理程序BpmProcessor动作,该动作使用jBPM命令API来调用jBPM。 该操作采用流程定义名称,并创建并启动流程的新实例。 在这种情况下,进程本身是在单独的线程上异步执行的,这意味着服务在进程运行时将答复返回给调用者。

集成还实现了两个jBPM动作处理程序类-EsbActionHandler和EsbNotifier。 EsbActionHandler是一种请求-响应类型的操作,它将一条消息放在服务总线上,然后等待响应。 此集成的体系结构如图6所示。EsbActionHandler向用户服务发送请求消息,并将执行的过程令牌置于等待状态。 用户服务的执行完成后,它将调用特殊的JBPM服务,该信号表示等待过程令牌继续。

图6 JBPM / ESB集成架构

结果,这种集成为具有多个令牌的进程提供了异步执行支持(例如,在fork / join或并行循环执行的情况下, 请参见上文 )。

另一方面,EsbNotifier仅在服务上丢弃消息并继续其处理。 与JBossESB的交互本质上是异步的,并且在服务执行时不会阻塞流程实例。

同步调用流程

如前所述,BpmProcessor异步调用业务流程,这在服务编排中并不总是理想的情况。 流程执行的结果可以用作服务回复。 ESB / JBPM集成提供了额外的支持来实现此方案17

BpmProcessor操作支持附加的配置参数– Reply-to-originator 。 如果此参数设置为true ,则BPMProcessor在新创建的流程实例的JBPM执行上下文中存储服务调用者的ReplyTo信息。 然后,EsbNotifier可以使用ReplyTo信息,通过将reply-to-originator指定为notifier的目的地来传递流程执行结果。 为了使该机制起作用,必须使用MEP Oneway定义服务的调用过程。

异常处理

从业务流程中调用服务时,异常不仅会在节点执行(服务调用)中发生,而且还会在被调用服务的执行中发生。 这种情况需要特殊的异常处理程序。 可以将此处理程序定义为BpmProcessor动作的一部分,并允许控制从服务调用的转换–成功或错误时的不同转换。

JBPM工具

JPDL是一种基于XML的语言,因此以XML表示。 为了简化业务流程的创建和分析,JBoss提供了一个Eclipse插件,用于可视化创建和操作JPDL流程(图7)。

该编辑器允许以图形和基于XML的方式查看业务流程,还支持从Eclipse项目直接部署到JBoss服务器。

图7 JPDL编辑器

总体评价

JBoss ESB / jBPM的结合提供了一个非常强大,可扩展和灵活的平台,用于基于现有企业资产创建面向服务的解决方案。 它提供了用于实施此类解决方案的所有主要组件,包括:

  • 灵活的ESB平台,允许将现有功能与服务实现(服务管道)所需的其他业务和基础架构处理轻松组合。
  • 强大的转换引擎(Smooks),简化了从专有数据模型(由现有功能提供)到解决方案使用的语义数据模型的转换实施。 支持可视化定义转换的工具进一步简化了此类实现。
  • 轻量级可扩展的jBPM实现有助于基于现有NAVTEQ功能构建复合服务。

本文介绍的JBoss中间件评估基于NAVTEQ中构建的几个VMS解决方案原型。 该原型基于针对管理用户,位置和路线的特定于域的模型,并包括作为现有Web服务的包装和直接在SOA平台内部直接实现的服务的几种ESB服务。 它还包括使用jBPM实现的几种复合(和分层复合18 )服务。

我们目前还在评估基于JBoss中间件的性能和可伸缩性,以及针对SOA解决方案监视和管理的JBoss Operations Network 19 (JON)的使用情况。

致谢

我要感谢我的NAVTEQ同事,特别是Robert Camp,Ian Mondragon和Jeffrey Herr,以及JBoss解决方案架构师,特别是Ray Ploski和Aaron Pestel,他们实现了原型并描述了他们的结果。

附录。

package com.navteq.jbpm.parallel;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;

 /**
* specifies configurable parallel execution behaviour.
*
*/
public class ParallelStart implements ActionHandler { private static final long serialVersionUID = 1L; // The name of the variable holding loop count private String loopCount ; // The name of the variable current count (stored in the token variable scope) private String currentCount ; // The list of the array variables . Each array has to be of the of the loop count
// size. An appropriate element is stored in the token context scope
private Map<String, String> variables public void execute(ExecutionContext context) { // Load loop counter int counter; try { counter = (Integer)context.getContextInstance().getVariable( loopCount ); } catch (Exception e){ System.out.println( "Can't load loop counter " ); e.printStackTrace(); return ; } // Build splitter map Map<String, Object[]> splitMap = null ; if (( variables != null ) && ( variables .size() > 0)){ splitMap = new HashMap<String, Object[]>(); Set <String> keys = variables .keySet(); for(String v : keys){ try { Object[] values = (Object[])context.getContextInstance().getVariable(v); splitMap.put(v, values); } catch (Exception e){ System.out.println( "Can't load values for variable " + v); e.printStackTrace(); continue ; } } } // Get default transition Token token = context.getToken(); Node currentNode = token.getNode(); Transition tr = currentNode.getDefaultLeavingTransition(); // execute default transition loop times for(int i = 0; i < counter; i++){ Token childToken = new Token(token, tr.getName()+ i); ExecutionContext childExecutionContext = new ExecutionContext(childToken); childExecutionContext.getContextInstance().setVariable(FONT COLOR="#0000FF">currentCount, i, childToken); if (splitMap != null ){ // Populate variables Set<String> keys = splitMap.keySet(); for (String v : keys){ try { Object value = splitMap.get(v)[i]; childExecutionContext.getContextInstance().setVariable( variables .get(v), value, childToken); } catch (Exception e){ System.out.println( "Can't load " + i + " element for variable " + v); e.printStackTrace(); continue ; } } } // Start token execution currentNode.leave(childExecutionContext); } } }

清单1. Start Parallel执行处理程序

package com.navteq.jbpm.parallel;

import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;

public class ParallelEnd implements ActionHandler {

	private static final long serialVersionUID = 1L;

	/** spec if ies wether what type of hibernate lock should be acquired.  null value defaults to LockMode. for ce */
	String parentLockMode;
	// The name of the variable holding loop count
	private String loopCount;
	// The name of the variable current count (stored in the token variable scope)
	private String currentCount ;
	// The list of the array variables . Each array has to be of the of the loop count
	// size. An appropriate element is stored in the token context scope
	private Map<String, String> variables ;

	public void execute(ExecutionContext context) {

		// Get current token
		Token token = context.getToken();
		boolean isAbleToReactivateParent = token.isAbleToReactivateParent();

		if (!token.hasEnded()) {
			token.end( false );
		}

		// if this token is not able to reactivate the parent, 
// we don't need to check anything
if ( isAbleToReactivateParent ) { // the token arrived in the join and can only reactivate
// the parent once
token.setAbleToReactivateParent( false ); Token parentToken = token.getParent(); // Build replies array if (( variables != null ) && ( variables .size() > 0)){ // current counter int current = (integer)context.getContextInstance().getVariable( currentCount ,token); // for every variable Set<String> keys = variables .keySet(); for (String v : keys) { Object value = context.getContextInstance().getVariable(v, token); String res = variables .get(v); Object[] values = (Object[]) context.getContextInstance().getVariable(res); if (values == null ) { // Get array size int loopSize = (integer) context.getContextInstance().getVariable(loopCount); // Get variable type Class t = value.getClass(); // Create an array of a variable type values = (Object[])Array.newInstance(t, loopSize); } values[current] = value; context.getContextInstance().setVariable(res, values); } } if ( parentToken != null ) { // Get context and lock session JbpmContext jbpmContext = context.getJbpmContext(); Session session = (jbpmContext != null ? jbpmContext.getSession() : null ); if (session != null ) { LockMode lockMode = LockMode. for CE; if ( parentLockMode != null ) { lockMode = LockMode.parse( parentLockMode ); } session.lock(parentToken, lockMode); } // Check if we can reactivate parent boolean reactivateParent = mustParentBeReactivated(parentToken, parentToken.getChildren().keySet().iterator() ); // if the parent token needs to be reactivated from this join node if (reactivateParent) { // write to all child tokens that the parent is already reactivated Iterator iter = parentToken.getChildren().values().iterator(); while ( iter.hasNext() ) { ((Token)iter.next()).setAbleToReactivateParent( false ); } // write to all child tokens that the parent is already reactivated ExecutionContext parentContext = new ExecutionContext(parentToken); token.getNode().leave(parentContext); } } } } public boolean mustParentBeReactivated(Token parentToken, Iterator childTokenNameIterator) { boolean reactivateParent = true; while ( (childTokenNameIterator.hasNext()) && (reactivateParent) ){ String concurrentTokenName = (String) childTokenNameIterator.next(); Token concurrentToken = parentToken.getChild( concurrentTokenName ); if (concurrentToken.isAbleToReactivateParent()) { reactivateParent = false ; } } return reactivateParent; } }

清单2. End Parallel执行处理程序

package com.navteq.jbpm.actionHandlers;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;

public class ExceptionActionHandler implements ActionHandler {

	private static final long serialVersionUID = 1L;

	private String destination ;

	@Override
	public void execute(ExecutionContext context) throws Exception {

		Token token = context.getToken();
		Node sourceNode = token.getNode();
		Throwable throwable = context.getException();
		System. out .println( "Caught Exception " + throwable.getMessage() + " in node " + sourceNode.getName());
		Node targetNode = context.getProcessDefinition().getNode( destination );
		token.setNode(targetNode);
		token.signal();
	}

清单3异常处理程序


1 ESB消息操作指南-章节。 1个

2在原始的RosettaNet ESB中,所有通信都是消息传递。

3如果服务MEP是单向的,则请求/回复调用的使用将导致死锁,因为在这种情况下,服务将永远不会传递回复。

4 JSR 181:Java平台的Web服务元数据

5 http://www.javalinuxlabs.org/drupal/

6可以在一组配置文件中配置多个服务。

7或者,可以在JBoss运行时中直接定义传输

8 ESB工具参考指南

9 http://www.smooks.org/documentation/documentation-smooks-1-1-x/user-guide

10 http://www.infoq.com/articles/event-streaming-with-smooks

11 JBoss企业SOA平台

12个 关于烟雾的性能数据

13 jBPM用户指南

14许多专有的BPEL扩展,例如IBM的流程服务器和Oracle Process Manager中的扩展,都可以克服此限制

15个 流程组件模型:下一代工作流程?

16 SOA ESB jBPM集成指南

17 http://lists.jboss.org/pipermail/esb-issues/2008-July/008059.html

18我将作为组合服务的组成部分实现的服务称为分层组合服务

19 老板运营网络

翻译自: https://www.infoq.com/articles/jboss-esb-jbpm/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

jboss jbpm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值