IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

使用 BPEL4WS 的业务流程: 学习 BPEL4WS,第 3 部分

各种活动以及内存中模型

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Matthew Duftler (duftler@us.ibm.com), 软件工程师, IBM
Rania Khalaf (rkhalaf@us.ibm.com), 软件工程师, IBM

2002 年 10 月 01 日

专栏图标最近发布的 Web 服务的业务流程执行语言(Business Process Execution Language for Web Services,BPEL4WS)规范,其定位是成为整合方面的 Web 服务标准。本系列文章的目的是让读者对 BPEL4WS 语言的不同组成部分有所了解,并教读者如何创建自己完整的流程。本系列文章前面的部分对这种语言进行了概述,并且引领读者创建了他们的第一个简单的流程。这一部分将更详细介绍每一种活动。我们还将介绍如何在内存中表示和操作各种 BPEL4WS 构造。

介绍

既然我们已经学习了 BPEL4WS 语言的基础知识(请参阅 第 1 部分),并且我们已经创建了一个简单的示例(请参阅 第 2 部分),那我们就来更详细地研究如何使用每种活动。在本文中,我们将提供对每个 BPEL4WS 活动的详细描述。我们还将描述被 BPWS4J(IBM 的实现,可以从 alphaWorks上获得)用来表示 BPEL4WS 流程的内存中表示,并给出一个示例解释模型的使用。





回页首


基本活动

基本活动是与外界进行交互最简单的形式。它们是无序的个别步骤,与服务进行交互、操作传输数据或者处理异常。

Web 服务交互

流程可以用三种活动与外界进行交互: <invoke><reply><receive> 。和我们在前面的文章中看到的一样,流程的伙伴之间通过使用这三种活动发生交互。通过指定 portType、操作以及伙伴,这些活动中的每一种活动标识出它所属于的 Web 服务调用。

流程用 <invoke> 活动调用伙伴提供的 Web 服务。除了 portType、伙伴和操作之外,调用还为正被调用的操作的输入和输出指定输入容器和输出容器。调用可以是同步的(请求/响应),也可以是异步的(单向)。在后一种情况中,只需要输入容器。

业务流程通过一对 <receive><reply> 活动为它的伙伴提供服务。receive 表示流程提供的 WSDL 操作的输入。如果流程需要向发送消息的伙伴返回一个应答,那么 reply 活动就是必需的。在流程中可以定义多个 reply 活动来回答该伙伴的调用;但是,一次只可能有一个匹配的 <reply> 成为激活的。适当的 reply 活动的匹配是在运行时进行的,此时流程寻找这样一个活动 ― 准备运行并拥有和 <receive> 相同的 portType、操作和伙伴。例如,流程可能将接收到的消息放在某个容器(容器 A)中,如果满足某个条件就返回容器 A 中的消息,否则就返回来自另一个容器(容器 B)的消息。在这种情况下,receive 将具有两个带有该项条件的链接;这两个链接将链接到两个 reply 活动,只有其中一个 reply 活动将激活并向伙伴返回正确的消息。

流程生命周期
只有当一条消息被发送给特别标记的 <receive> 活动或 <pick> 活动时,才可能创建一个业务流程实例。几个 receive 活动指出通过将 createInstance 属性设置为真,它们就能够创建一个流程实例。 <pick> 活动将拥有一个 onMessage 元素,这个元素也具有 createInstance 属性并且被设置为真。在本文稍后的部分将更详细地说明 <pick> 活动。第一个被这样标记并且获得了一条消息的 receive 活动将创建实例,接着,其余 receive 活动在该实例中就被当作常规 receive 活动来对待。

此时,您可能想知道怎样才能创建第二个实例。相关性用于弄清楚传入的消息要发送给哪个实例。所有可以启动流程的 receive 和 onMessage 都必须拥有相同的相关性设置。所以,当一条消息进来的时候,流程对其进行检查以了解它是否包含与现有的实例相匹配的相关性设置。如果这条消息符合条件,流程就将它发送给那个实例。否则,流程将根据与传入的消息的操作、portType 和伙伴信息相匹配的 receive 活动创建一个新实例。在本系列以后的文章中将详细讨论 BPEL 中的相关性。

操作数据: <assign> 活动

<assign> 活动可以用于将数据从一个容器复制到另一个容器,也可以用于通过使用表达式构造和插入新数据。使用表达式主要是由于需要执行简单的计算(如递增序列号)而激发的,这些简单计算是描述业务协议行为所必需的。表达式对消息选择、属性和文字常量进行操作,以便为容器属性或选择产生新的值。

每个 <assign> 活动包含一个或多个 <copy> 元素;每个 <copy> 元素正好包含一个 <from> 元素和一个 <to> 元素。有各种形式的 <from> 元素和 <to> 元素,要记住的最重要的事情就是,从源( <from> )复制到目的地( <to> )的值必须是类型兼容的。

一种较简单的 <from> 形式仅用名称指定容器。当使用仅指定一个容器的源时,将复制整个消息;这意味着目的地也必须仅指定一个容器。

更复杂一点的 <from> 形式指定一个容器以及该容器中的一个部件。当使用这种形式时,目的地也必须指定一个容器及其中的一个部件。

第三种形式的 <from> 指定要用 XPath 进行求值的一般表达式。该表达式可以是 XPath 允许的任何东西,只要该表达式返回 XPath 值类型(字符串、数值或布尔)。当使用这种形式时,目的地必须指定一个容器及其中的一个部件。

简而言之,消息可以覆盖其他消息,消息部件可以覆盖其他消息部件。因为表达式不返回完整的消息,所以它们只被用于覆盖消息部件。

因为有必要使 XPath 表达式能够访问来自流程的信息,所以 BPEL4WS 引入了几个 XPath 扩展函数。在标准的 BPEL4WS 名称空间 http://schemas.xmlsoap.org/ws/2002/07/business-process/中定义这些扩展函数,前缀 bpws与这个名称空间相关联。

这些函数之一的一个示例如下所示。

    bpws:getContainerData("containerName", "partName", "locationPath"?) 

在这个示例中, containerName是容器的名称, partName是该容器中一个部件的名称, locationPath是这个指定部件中的绝对位置路径,它是可选的。

任何希望检索来自流程中某个容器的数据的 XPath 表达式都可以使用 bpws:getContainerData() 函数,就好像它是内置的 XPath 函数一样。

:除了复制消息、部件和表达式外, <assign> 活动还可以用于将服务引用复制到伙伴链接以及从伙伴链接复制服务引用。

其他基本活动

在 BPEL4WS 中可以通过 <throw> 活动发出故障信号。为了使您能够使用故障处理程序来最终捕获故障并对其进行处理,该语言要求故障有一个全局唯一的 QName。可以添加一个可选的容器,该容器指向可以找到与故障相关的数据的位置。例如,您可能有一个发出某种故障的信号的 <throw> 活动,然后可以有一个具有 <reply> 的故障处理程序,该 <reply> 向伙伴发送关于故障的信息。该 reply 将使用故障活动中指定的容器。

<terminate> 活动可以用于立即放弃执行着该终止活动的业务流程实例中的所有执行。

<wait> 活动使流程能够等待一段特定的时间间隔,或者一直等到某个截止期限为止。

<empty> 活动什么都不做。如果您需要捕获一个故障并抑制它,您可以使用这个活动。





回页首


结构化活动

结构化活动规定了一组活动发生的顺序。结构化活动通过将业务流程执行的基本活动整合到结构中来描述业务流程是如何被创建的,这些结构表达了业务协议中所涉及的控制模式、数据流、故障和外部事件的处理以及在流程实例之间进行消息交换的协调。

如同我们在这个文章系列较早的文章中描述过的, <sequence> 活动包含一个或多个顺序执行的活动。活动按照它们在 <sequence> 元素中出现的顺序被执行。当 <sequence> 中的最后一个活动已经完成的时候, <sequence> 活动本身就完成了。

<switch> 活动起的作用与许多传统编程语言中出现的 switch 构造很相似。switch 活动中有一个由 <case> 元素定义的、由一个或多个条件分支组成的有序列表,后面跟着一个可选的 <otherwise> 元素。每个 <case> 分支指定一个布尔 XPath 表达式,按照表达式出现的顺序对它们求值(条件表达式的求值所使用的逻辑,与前面讲述 <assign> 的部分所描述的用于一般表达式的逻辑几乎相同)。第一个布尔表达式值为真的 <case> 元素的子活动将获得执行。如果没有哪个 <case> 元素的条件为真,则执行 <otherwise> 元素的子活动。如果没有指定 <otherwise> 元素,则会有一个隐含的包含一个 <empty> 活动的 <otherwise> 。当选定的分支完成时, <switch> 活动也就完成了。

<while> 活动重复执行它的子活动,直到对指定的布尔条件求得的值不再为真。条件被当作 XPath 表达式进行求值。

<pick> 活动包含一组事件处理程序。每个处理程序包含一个活动,处理程序在 pick 已经启动且处理程序正等待的事件发生时运行。处理程序包括警报处理程序,警报处理程序指定持续时间或截止期限,还包括消息处理程序(onMessage),消息处理程序等待来自某个特定伙伴、portType 和操作三元组的消息。消息处理程序能够按照与 receive 相同的方式创建一个流程实例,上面关于流程生命周期的部分描述了这种方式(使用 createInstance 属性)。只有第一个要接收它的事件的事件处理程序才会运行,一旦该处理程序的活动完成, <pick> 就将完成。

<scope> 活动为嵌套在其中的活动提供故障处理功能和补偿处理功能。在即将发表的关于故障处理和补偿的文章中将更详细地介绍作用域(scope)。

<flow> 构造提供了以并行方式运行活动的能力,还提供了定义防护性链接的能力。它可以包含任意数量的活动。当流被启动后,这个流中的所有活动就都做好了运行的准备,除非这些活动具有还没有求得值的传入的链接。流定义了一组链接,这些链接的源活动和目标活动都必须嵌套在这个流中。

链接对于如何将流程的活动设置为运行施加了自己的约束。一旦一个活动完成了,它就对离它而去的链接上的任何条件进行求值。如果没有定义任何条件且活动已经正常完成,则所有条件的求值均为真。如果活动发生了故障,或者无法运行,那么活动向它所有的外发链接报错。另一方面,有传入链接的活动不得不等待,直到获得它所有链接传下来的值,方可运行。该活动还需要对它所包含的活动有控制权。例如,假设它是 sequence 中的第二个活动并且它的所有链接都已传入,如果该 sequence 中的第一个活动尚未完成,那么它也不会运行。一旦它拥有了这个控制权并且知道了它所有传入的链接的值,它就对一个被称为连结条件的条件求值。连结条件包含传入的链接的状态,如果活动要运行,则连结条件的求值必须为真。如果其求值为假,那么活动将发出一个连结失败的信号并且异常结束。如果该活动的隐式链接(来自父活动的控制权)为真且活动的各显式链接中有任意一个为真,那么缺省连结条件就为真。所有的链接条件均为 XPath 表达式。





回页首


BPWS4J 模型

既然我们已经更详细地介绍了该语言,就让我们看一看用于创建和表示 BPEL4WS 流程的内存中表示的一种机制。我们称这组 API 为 BPWS4J 模型。这个“模型”包括一个工厂机制以及用来表示 BPEL4WS 构造的所有接口。

应用程序先通过 BPWSFactory 的静态 newInstance 方法获得一个 BPWSFactory 实例。newInstance 方法使用下面有序的查找过程来确定要装入的 BPWSFactory 实现类:

  • 检查 com.ibm.bpws.factory.BPWSFactory 系统属性。
  • 检查 JRE 目录下的 lib/bpws.properties 文件。键名与上面的系统属性名称一样。
  • 使用平台缺省值(将随实现而不同)。

:还有一个静态的 newInstance 方法,它以工厂实现的全限定类名作为参数,这种情况不使用上述过程。

一旦获得了一个 BPWSFactory 实例,就可以调用方法 newBPWSProcess 来创建一个新 BPWSProcess。一旦获得了那个流程,它就充当一个可以用来创建将组成完整流程的其余项的工厂。

清单 1 是一个以编程的方式构造包含一个 <receive>/<reply> 序列的流程的示例:


清单 1. 构造一个 <receive>/<reply> 序列
    BPWSFactory factory = BPWSFactory.newInstance(); 
    BPWSProcess process = factory.newBPWSProcess(); 
    String tns = "urn:echo:echoService"; 
    Containers containers = process.createContainers(); 
    Container container = process.createContainer(); 
    Partners partners = process.createPartners(); 
    Partner partner = process.createPartner(); 
    Sequence sequence = process.createSequence(); 
    Receive receive = process.createReceive(); 
    Reply reply = process.createReply(); 
    process.setName("echoString"); 
    process.setTargetNamespace(tns); 
    partner.setName("caller"); 
    partner.setServiceLinkType(new QName(tns, "echoSLT")); 
    partners.addPartner(partner); 
    process.setPartners(partners); 
    container.setName("request"); 
    container.setMessageType(new QName(tns, "StringMessageType")); 
    containers.addContainer(container); 
    process.setContainers(containers); 
    receive.setName("EchoReceive"); 
    receive.setPartner(partner); 
    receive.setPortType(new QName(tns, "echoPT")); 
    receive.setOperation("echo"); 
    receive.setContainer(container); 
    receive.setCreateInstance(Boolean.TRUE); 
    sequence.addActivity(receive); 
    reply.setName("EchoReply"); 
    reply.setPartner(partner); 
    reply.setPortType(new QName(tns, "echoPT")); 
    reply.setOperation("echo"); 
    reply.setContainer(container); 
    sequence.addActivity(reply); 
    sequence.setName("EchoSequence"); 
    process.setActivity(sequence); 

由上面的序列步骤创建的内存中表示应该表示清单 2 中的流程。


清单 2. 序列步骤的内存中模型
    <process name="echoString" 
             targetNamespace="urn:echo:echoService" 
             xmlns:tns="urn:echo:echoService" 
             xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/"> 
      <partners> 
        <partner name="caller" 
                 serviceLinkType="tns:echoSLT"/> 
      </partners> 
      <containers> 
        <container name="request" 
                   messageType="tns:StringMessageType"/> 
      </containers> 
      <sequence name="EchoSequence"> 
        <receive name="EchoReceive" 
                 partner="caller" portType="tns:echoPT" 
                 operation="echo" container="request" 
                 createInstance="yes"/> 
        <reply name="EchoReply" 
               partner="caller" portType="tns:echoPT" 
               operation="echo" container="request"/> 
      </sequence> 
    </process> 

刚才阐述过的模式(将流程用作工厂,然后把构造的项添加到适当的父项中)用在整个内存中模型中。

可以通过工具使用 BPWS4J 模型,也可以由那些想以编程的方式创建流程而不是读或生成流程的用户来使用 BPWS4J 模型。





回页首


下一次

在本系列的下一篇文章中,我们将讲述如何使用 BPWS4J 可视化编辑器可视化地创建 BPEL 流程。其后的一篇文章将以我们已经看到的贷款批准样本为基础,阐述链接和数据操作的使用。



参考资料



作者简介

Matthew J. Duftler 是 IBM T.J. Watson Research Center 的 Component Systems 小组的一名软件工程师。他是 Apache SOAP 的原作者之一,是 JSR110(Java APIs for WSDL)的带头人之一,还是 IBM BPEL4WS 引擎的创作者之一。您可以通过 duftler@us.ibm.com 与 Matthew Duftler 联系。


Rania Khalaf 是 IBM TJ Watson Research Center 的 Component System 小组的一名软件工程师。2001 年,她从 MIT 获得学士学位和工程硕士学位后进入 IBM。Rania 是 IBM BPEL4WS 引擎的创作者之一,您可以从 alphaWorks 上获得 BPWS4J。您可以通过 rkhalaf@watson.ibm.com与作者联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款