版本 1.02002 年 8 月 9 日作者(按字母顺序):Francisco Curbera,IBM Yaron Goland,BEA Systems Johannes Klein,Microsoft Frank Leymann,IBM Dieter Roller,IBM Satish Thatte,Microsoft(编辑) Sanjiva Weerawarana,IBM Copyright 2001-2002 BEA Systems, International Business Machines Corporation, Microsoft Corporation, Inc. All rights reserved. 提供、分发或以其它方式传播本规范所包含的信息并未授予您使用 IBM 或 Microsoft 或 BEA 和/或任何其它第三方所拥有或控制的知识产权的许可证(无论是明示的还是默示的)。IBM、Microsoft、BEA 和/或任何其它第三方可能拥有与本文档内容有关的各项专利权、专利应用权、商标权、版权或其它知识产权。提供本文档并未授予用户使用 IBM 或 Microsoft 或 BEA 或任何其它第三方的专利、商标、版权或其它知识产权的任何许可证。此处举例所用的公司、组织、产品、域名、电子邮件地址、徽标、人员、地点和事件均属虚构。无意也不应推测为与任何真实的公司、组织、产品、域名、电子邮件地址、徽标、人员、地点或事件有任何关联。 此处包含的规范和信息以“按现状”的基础提供,并在适用法律许可的最大范围内被允许,IBM 和 Microsoft 和 BEA 以“按现状并可能存在各种错误”的基础提供本文档,特此声明免除所有(无论是明示的、默示的,还是法定的)其它保证和条件,包括(但不限于)对与本文档有关的适销性、适用于某特定用途、响应的准确性或完整性、结果、技艺精湛的成果、无病毒和无疏忽的默示保证、责任或条件(如果有的话)。此外,对所有权、平静享用、平静占有、与描述相符或与本文档有关的知识产权的非侵权性不提供任何保证或条件。 在任何情况下,IBM 或 MICROSOFT 或 BEA 都不对任何其它方获取替代产品或服务的费用、利润损失、使用损失、数据丢失、或者任何意外的、有连带关系的、直接的、间接的或特殊的损害负责,不管这类损害是由合同、侵权或保证引起的,还是由此外的方式或与本文档有关的任何其它协定引起的,也不管该方是否已被预先告知可能发生这类损害。 摘要 本文为指定基于 Web 服务的业务流程行为定义了一种表示方法。这种表示方法被称为 Web 服务的业务流程执行语言(Business Process Execution Language for Web Services)(以下简称为 BPEL4WS)。用 BPEL4WS 表示的流程只能通过使用 Web 服务接口来导出和导入功能。 描述业务流程的方式有两种。可执行业务流程可以模拟业务交互中的参与者的实际行为。相对而言,业务协议使用流程描述来指定涉及协议的每一方能相互看到的消息交换行为,但并不公开他们的内部行为。业务协议的流程描述被称为抽象流程。BPEL4WS 应被用来模拟可执行流程和抽象流程的行为。 BPEL4WS 提供了正式指定业务流程和业务交互协议的语言。这样做是为了扩展 Web 服务交互模型并使它支持业务事务。BPEL4WS 所定义的可互操作的集成模型应该能够促进在企业内和企业间的自动流程集成的扩展。 状态 这里发布的是 BPEL4WS 规范的最初的公开草案。我们期待着不少扩展被增加到 BPEL4WS 的功能集(在本文的末尾将简要地讨论这些扩展)。BPEL4WS 代表了 XLANG 和 WSFL 规范中的概念的融合。BPEL4WS 规范取代了 XLANG 和 WSFL。 BPEL4WS 和相关规范以“按现状”的基础提供,仅供审阅和评估。IBM、Microsoft 和 BEA 希望在不久的将来向您征稿,并得到您的建议。IBM、Microsoft 和 BEA 都不以任何方式作出关于这些规范的保证或表示。 内容 1. 引言
2. 词语约定
3. 与 WSDL 的关系
4. 定义业务流程 4.1. 第一个示例 4.2. 业务流程的结构 4.3. 语言的可扩展性 4.4. 业务流程的生命周期
5. 服务链接、伙伴和服务引用 5.1. 服务链接 5.2. 伙伴 5.3. 服务引用
6. 消息属性 6.1. 动机 6.2. 定义属性
7. 相关性 7.1. 消息相关性 7.2. 定义和使用相关集
8. 数据处理 8.1. 表达式 8.1.1. 布尔表达式 8.1.2. 值为截止期限的表达式 8.1.3. 值为持续时间的表达式 8.1.4. 一般表达式 8.2. 容器 8.3. 赋值 8.3.1. 赋值的原子性 8.3.2. 赋值示例 8.4. 抽象流程与可执行流程间的差别总结
9. 基本活动 9.1. 每个活动的标准属性 9.2. 每个活动的标准元素 9.3. 调用 Web 服务操作 9.4. 提供 Web 服务操作 9.5. 更新容器内容 9.6. 发出故障信号 9.7. 终止服务实例 9.8. 等待 9.9. 不做任何事
10. 结构化的活动 10.1. Sequence 10.2. Switch 10.3. While 10.4. Pick 10.5. Flow 10.5.1. 链接语义 10.5.2. 死路删除(Dead-Path-Elimination,DPE) 10.5.3. Flow 图的示例 10.5.4. 链接和结构化的活动
11. 作用域 11.1. 业务流程中的错误处理 11.2. 补偿处理程序 11.2.1. 定义补偿处理程序 11.2.2. 调用补偿处理程序 11.3. 故障处理程序 11.3.1. 隐式故障处理程序和补偿处理程序 11.3.2. 活动终止的语义 11.3.3. 故障处理程序和补偿处理程序中的故障处理 11.4. 可序列化的作用域
12. 示例 12.1. 运输服务 12.1.1. 服务描述 12.1.2. 消息属性 12.1.3. 流程 12.2. 贷款审批 12.2.1. 服务描述 12.2.2. 流程 12.3. 多个启动活动 12.3.1. 服务描述 12.3.2. 流程
13. 未来的发展方向
13.1. 作用域 13.1.1. 容器 13.1.2. 事件处理程序 13.1.3. 重叠作用域 13.1.4. 原子作用域 13.1.5. 补偿 13.2. 生命周期和查询 13.2.1. 暂挂/恢复 13.2.2. 查询 13.3. 服务组成 13.4. 与 WS-Transaction 规范的关系
14. 安全性注意事项
15. 致谢
16. 参考资料
附录 A 标准故障
附录 B 属性和缺省值
附录 C 协调协议 BPEL4WS 作用域的协调协议
附录 D - XSD 模式 BPEL4WS 模式 服务链接类型模式 服务引用模式 消息属性模式
1. 引言Web 服务的努力目标是通过使用 Web 标准实现应用程序间的通用的互操作性。Web 服务使用松散耦合的集成模型以支持各种领域(包括企业到消费者、企业到企业和企业应用程序集成)中的各种系统的灵活集成。以下基本规范最初定义了 Web 服务空间:SOAP、Web 服务描述语言(Web Services Description Language,WSDL)和统一描述、发现和集成(Universal Description,Discovery,and Integration,UDDI)。SOAP 为基本服务的互操作性定义了 XML 消息传递协议。WSDL 采用了用于描述服务的公共语法。UDDI 为系统地发布和发现服务提供了所需的基础结构。这些规范共同使应用程序遵循一个松散耦合、与平台无关的模型来找到对方并进行交互。
系统集成需要的不仅仅是通过使用标准协议来进行简单交互的能力。仅当应用程序和业务流程能够通过使用标准流程集成模型来集成复杂的交互时才能发挥 Web 服务作为集成平台的全部潜力。WSDL 所直接支持的交互模型仅仅是同步或不相关的异步交互的无状态模型。业务交互的模型通常假设在涉及双方或多方的有状态的长期运行的交互中的同步和异步对等消息交换序列。为了定义这种业务交互,需要对业务流程在其交互中所用的消息交换协议的正式描述。这种业务协议的定义涉及准确地指定涉及协议的每一方都能相互看到的消息交换行为但并不公开它们的内部实现。出于两个原因,需要把业务流程行为分为公共部分和内部部分(或私有部分)。一个原因是企业显然不想让它的业务伙伴知道它的所有的内部决策和数据管理。另一个原因是(即便并不是这种情况)通过把公共流程和私有流程分开,您能够改变流程实现的私有部分而不会影响到公共业务协议。 必须用平台无关的方式来明确地描述业务协议,业务协议必须包括在跨企业业务中的所有重要行为部分。这样,每位参与者可以理解业务协议并为遵守它而作准备,每位参与者不必进行人工协商,目前,人工协商的过程大大增加了建立跨企业自动业务流程的难度。 描述业务协议需要哪些概念?这些概念与描述可执行流程所需的概念之间是什么关系?为了回答这些问题,请从以下几个方面来考虑:
- 业务协议总是包括数据相关的行为。例如,供应链协议依赖于这样的数据:定单中的单项产品的数量、定单的总价或交付的截止期限。在这些情况下定义业务目的需要使用条件和超时构造。
- 对于业务协议来说,指定异常条件及其后果(包括恢复序列)的能力至少与定义“一切正常运行”时的行为的能力一样重要。
- 长期运行的交互包括多个工作单元,这些单元常常是嵌套的,每个单元有自己的数据要求。业务协议常常要求颗粒度不同的工作单元的结果(成功或失败)的跨伙伴协调。
如果我们想为跨企业业务协议提供准确的可预测的服务行为描述,那么我们需要一种丰富的流程描述表示方法,它的许多特点使我们想起了可执行语言。公共消息交换协议与可执行内部流程的主要区别是内部流程用丰富的私有方式来处理数据,但在公共协议中并不需要描述这些数据。 在考虑业务协议的数据处理部分时,对比网络通信协议和业务协议是有益的。网络协议定义了在通信线路上传输的协议信封的形式和内容,这些协议所描述的协议行为完全由这些信封中的数据来决定。换句话说,在有关协议的数据和“有效负载”数据之间存在清楚的物理分界线。在业务协议中,这种分界线是模糊的,这是因为有关协议的数据往往被嵌入在其它应用程序数据中。 BPEL4WS 使用消息属性这个概念来识别嵌入在消息中的有关协议的数据。属性可被看作有关公共部分的“透明的”数据,与之相对的是内部/私有函数使用的“不透明的”数据。透明的数据直接影响公共业务协议,不透明的数据主要是对后端系统有重要意义,它影响业务协议的唯一方式是产生不确定性,因为它影响决定的方式是不透明的。我们的原则是被用来影响业务协议的行为的任何数据必须是透明的,所以必须被视为属性。 不透明的数据的隐式影响表现为涉及业务协议的服务行为中的不确定性。请考虑购买协议的示例。卖方的服务接收购买定单并根据多个标准(包括商品是否有货和买方的信用)作出接受或拒绝的响应。显然,决定过程是不透明的,但是决定的事实必须在外部业务协议中作为行为的多种选择被反映出来。换句话说,协议要求在卖方的服务行为中有类似 switch 活动的东西但分支的选择是不确定的。通过把不确定的或不透明的值(通常是从可能的值的枚举集中选出)赋给消息属性,可以模拟这种不确定性。这样,属性可被用于定义表示各种行为选择的条件行为而不公开实际决策过程。为了表示公共行为的本质同时隐藏私有部分,BPEL4WS 显式地允许使用不确定的数值。 定义业务协议和定义可执行业务流程所需的概念非常相似。定义业务协议所需的概念和定义可执行业务流程的所需的概念组成了统一体,BPEL4WS 被设计成包括这个统一体。BPEL4WS 所定义的模型和语法可被用于描述基于流程和它的伙伴间的交互的业务流程的行为。与每个伙伴的交互是通过 Web 服务接口进行的,在接口级别上关系的结构被封装在我们称之为的服务链接中。BPEL4WS 流程定义了与这些伙伴交互的多个服务交互是怎样协调的以达到业务目的,还定义了这种协调所需的状态和逻辑。BPEL4WS 还引入了一些系统的机制来处理业务异常和流程处理故障。最后,BPEL4WS 引入了一种机制,以用于定义在发生异常时或伙伴请求撤销时流程中单个或合成活动是怎样被补偿的。 应用 BPEL4WS 的基本概念的方式有两种。通过使用抽象流程概念,BPEL4WS 流程可以定义业务协议角色。例如,在供应链协议中,买卖双方是两个不同的角色,双方都有自己的抽象流程。他们的关系通常被模拟成服务链接。抽象流程使用所有的 BPEL4WS 概念但它对待数据处理的方式反映了描述业务协议公共部分所需的抽象程度。具体地说,抽象流程仅处理有关协议的数据。BPEL4WS 提供了把有关协议的数据识别为消息属性的方式。另外,抽象流程使用不确定的数值来隐藏行为的私有部分。 BPEL4WS 也可被用来定义可执行业务流程。流程的逻辑和状态决定了在每个业务伙伴那里进行的 Web 服务交互的性质和顺序,从而决定了交互协议。虽然从私有实现的角度来看并不需要完整地定义 BPEL4WS 流程,但是 BPEL4WS 为仅依赖于 Web 服务资源和 XML 数据的业务流程有效地定义了可移植的执行格式。此外,这种流程的执行以及与它们的伙伴交互的方式是一致的,与托管环境的实现所用的支持平台或编程模型无关。 即便在私有实现部分使用平台相关的功能的情况下(这在许多情况下是很有可能的,在多数的实际情况下更有可能),BPEL4WS 中抽象流程和可执行流程间的基本概念的模型的连续性可能将包含在业务协议中的公共部分作为流程或角色模板进行输出和输入,同时保持协议的目的和结构。从充分利用 Web 服务的角度来看,可以论证这是使用 BPEL4WS 的最有吸引力的前景,因为它支持大大提高自动化程度的工具和其它技术的开发从而降低了建立跨企业自动的业务流程的成本。 BPEL4WS 位于几个 XML 规范之上:WSDL 1.1、XML Schema 1.0 和 XPath1.0。WSDL 消息和 XML Schema 类型定义提供了 BPEL4WS 流程所用的数据模型。XPath 为数据处理提供支持。所有的外部资源和伙伴被表示成 WSDL 服务。BPEL4WS 所提供的可扩展性能支持这些标准的未来版本,即用于 XML 计算的 XPath 和相关标准。 2. 词语约定本文中的关键字“必须(MUST)”、“绝不可以(MUST NOT)”、“需要的(REQUIRED)”、“应该(SHALL)”、“将不(SHALL NOT)”、“应该(SHOULD)”、“不应该(SHOULD NOT)”、“推荐的(RECOMMENDED)”、“可以(MAY)”和“可选的(OPTIONAL)”将按 RFC2119 [13] 中的描述来解释。 名称空间 URI(常规形式是“some-URI”)表示 RFC2396 [14] 中定义的与应用程序相关或与内容相关的某个 URI。 本规范使用非正式的语法来描述 XML 片段的 XML 语法,如下: - 本语法以 XML 实例的形式出现,但其中的值代表数据类型而不是值。
- 粗体显示的语法是还未在本文中介绍过的语法,或在示例中有特别的意义。
- <-- description --> 是某些“其它”名称空间的元素的占位符(象 XSD 中的 ##other)。
- 字符按以下方式被附加到元素、属性和 <!-- descriptions -->:“?”(0 个或 1 个)、“*”(0 个或更多个)、“+”(1 个或更多个)。字符“[”和“]”用以表示所包含的项应作为一个与“?”、“*”或“+”字符有关的组被处理。
- 被“|”分隔且被“(”和“)”并排在一起的元素和属性应被理解为语法的候选式。
- XML 名称空间前缀(在下文中定义)被用来指出被定义的元素的名称空间。
- 以 <?xml 开头的示例包含足够的信息,这些示例符合本规范;其它示例是片断,需指定更多信息才能符合本规范。
所提供的 XSD schema 和 WSDL 定义是语法的正式定义 [xml-schema1][WSDL]。 3. 与 WSDL 的关系BPEL4WS 依赖于以下基于 XML 的规范:WSDL 1.1、XML Schema 1.0 和 XPath 1.0。在这些规范中,WSDL 对 BPEL4WS 语言的影响最大。BPEL4WS 流程模型位于由 WSDL 1.1 所定义的服务模型之上。位于 BPEL4WS 流程模型核心的是由 WSDL 描述的服务间的对等交互概念;流程及其伙伴都被建模成 WSDL 服务。业务流程定义了怎样协调流程实例与它的伙伴间的交互。在这个意义上,一个 BPEL4WS 流程定义提供和/或使用一个或多个 WSDL 服务,还通过 Web 服务接口提供流程实例相对于它的伙伴和资源的行为和交互的描述。也就是说,BPEL4WS 定义了交互中某个角色的业务流程遵守的消息交换协议。 BPEL4WS 业务流程的定义也遵循 WSDL 的分离模型,即把业务流程使用的抽象消息内容与部署信息(消息和 portType 与绑定和地址信息)分开。具体地说,BPEL4WS 流程用抽象 WSDL 接口(portType 和操作)来表示所有的伙伴以及与这些伙伴的交互;它并不引用流程实例使用的实际服务。BPEL4WS 流程是可重用的定义,可以不同的方式在不同的情况下被部署同时在它们之间保持一致的应用程序级别的行为。请注意,BPEL4WS 流程的部署的描述超出了本规范的范围。 4. 定义业务流程描述业务流程的方式有两种。可执行业务流程模拟业务交互中的参与者的实际行为。在可执行流程中,并不把业务流程分成从外部可看见的(或者说“公共”)部分和内部部分。相对而言,业务协议使用的流程描述指定了涉及协议的每一方的相互可以看见的消息交换行为并隐藏它们的内部行为。涉及业务协议的流程被称为抽象流程。一般来说,抽象流程是不可执行的。它们应被用来耦合 Web 服务接口定义与行为规范,这些行为规范既被用于约束业务角色的实现,也被用于以准确的词汇来定义业务协议中的每一方可以期望的对方行为。BPEL4WS 应被用来定义这两种流程。两者之间的差异仅限于这两种流程中用于数据处理的不同功能集。在数据处理这一节中,这些差异被准确地定义。 4.1. 第一个示例在详细描述业务流程的结构之前,这一节先讲述一个用于处理购买定单的 BPEL4WS 流程的简单的示例。这样做的目的是为了介绍 BPEL4WS 的最基本的结构和一些基本概念。 这个很简单的流程操作被表示在下图中。带点的线表示序列。任意地把序列组成一组表示并发的序列。实心箭头表示用于并发活动间的同步的控制链接。请注意这张图并不是 BPEL4WS 流程的正式图解表示法。这张非正式的图被用来帮助读者理解。 当收到客户的购买定单后,流程初始化三个并行的任务:计算定单的最终价格、选择承运人以及为定单安排生产和运输。虽然有些处理可以并行地进行,但是三个任务之间存在相互依赖的控制和数据。具体地说,在计算最终价格时需要运输价格,在全面安排实现计划时需要运输日期。在完成这三个任务后就可以开始处理发票并把发票交给客户。 
在下面的 WSDL 文档中显示了由服务提供给它的客户的 WSDL portType(purchaseOrderPT)。为了简单起见,业务流程所需的其它 WSDL 定义被包含在同一个 WSDL 文档中;具体地说,该文档还定义了一些 Web 服务的 portTypes,这些 Web 服务提供价格计算、运输选择和调度以及生产调度功能。请注意在 WSDL 文档中没有 bindings 或 service 元素。通过仅仅引用涉及流程的服务的 portType 并且不引用它们可能的部署,BPEL4WS 流程被“抽象地”定义。以这种方式定义的业务流程允许在兼容的服务的多次部署中再次使用业务流程定义。 在 WSDL 文档末尾的服务链接类型表示购买定单服务和与之交互的每一方的交互(请参阅服务链接、伙伴和服务引用)。无论 BPEL4WS 业务流程是为一种还是多种服务而定义的,服务链接类型可被用来表示这些服务间的依赖关系。每个服务链接类型最多可定义两个“角色”名称并列出每个角色必须支持的 portType 以便交互被成功执行。在这个示例中,“purchaseLT”链接类型和“schedulingLT”链接类型仅列出一个角色,这是因为在相应的服务交互中,其中的一方提供了所有的被调用操作:“purchaseLT”服务链接表示流程与请求客户之间的连接,其中只有购买定单服务需要提供服务操作(“sendPurchaseOrder”);“schedulingLT”服务链接表示购买定单服务与时间安排服务间的交互,其中只有后者的操作才被调用。其它两个服务链接类型“invoiceLT”和“shippingLT”定义了两个角色,这是因为发票计算的用户和运输服务(发票或运输安排)的用户都必须提供回调操作以使异步通知被异步地发送(“invoiceCallbackPT”portType 和“shippingCallbackPT”portType)。 <definitions targetNamespace="http://manufacturing.org/wsdl/purchase"
xmlns:sns="http://manufacturing.org/xsd/purchase"
xmlns:pos="http://manufacturing.org/wsdl/purchase"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/">
<import namespace="http://manufacturing.org/xsd/purchase"
location="http://manufacturing.org/xsd/purchase.xsd"/>
<message name="POMessage">
<part name="customerInfo" type="sns:customerInfo"/>
<part name="purchaseOrder" type="sns:purchaseOrder"/>
</message>
<message name="InvMessage">
<part name="IVC" type="sns:Invoice"/>
</message>
<message name="orderFaultType">
<part name="problemInfo" type="xsd:string"/>
</message>
<message name="shippingRequestMessage">
<part name="customerInfo" type="sns:customerInfo"/>
</message>
<message name="shippingInfoMessage">
<part name="shippingInfo" type="sns:shippingInfo"/>
</message>
<message name="scheduleMessage">
<part name="schedule" type="sns:scheduleInfo"/>
</message>
<!-- portTypes supported by the purchase order process -->
<portType name="purchaseOrderPT">
<operation name="sendPurchaseOrder">
<input message="pos:POMessage"/>
<output message="pos:InvMessage"/>
<fault name="cannotCompleteOrder"
message="pos:orderFaultType"/>
</operation>
</portType>
<portType name="invoiceCallbackPT">
<operation name="sendInvoice">
<input message="pos:InvMessage"/>
</operation>
</portType>
<portType name="shippingCallbackPT">
<operation name="sendSchedule">
<input message="pos:scheduleMessage"/>
</operation>
</portType>
<!-- portType supported by the invoice services -->
<portType name="computePricePT">
<operation name="initiatePriceCalculation">
<input message="pos:POMessage"/>
</operation>
<operation name="sendShippingPrice">
<input message="pos:shippingInfoMessage"/>
</operation>
</portType>
<!-- portType supported by the shipping service -->
<portType name="shippingPT">
<operation name="requestShipping">
<input message="pos:shippingRequestMessage"/>
<output message="pos:shippingInfoMessage"/>
<fault name="cannotCompleteOrder"
message="pos:orderFaultType"/>
</operation>
</portType>
<!-- portType supported by the production scheduling process -->
<portType name="schedulingPT">
<operation name="requestProductionScheduling">
<input message="pos:POMessage"/>
</operation>
<operation name="sendShipingSchedule">
<input message="pos:scheduleMessage"/>
</operation>
</portType>
<slnk:serviceLinkType name="purchaseLT">
<slnk:role name="purchaseService">
<slnk:portType name="pos:purchaseOrderPT"/>
</slnk:role>
</slnk:serviceLinkType>
<slnk:serviceLinkType name="invoiceLT">
<slnk:role name="invoiceService">
<slnk:portType name="pos:computePricePT"/>
</slnk:role>
<slnk:role name="invoiceRequester">
<portType name="pos:invoiceCallbackPT"/>
</slnk:role>
</slnk:serviceLinkType>
<slnk:serviceLinkType name="shippingLT">
<slnk:role name="shippingService">
<slnk:portType name="pos:shippingPT"/>
</slnk:role>
<slnk:role name="shippingRequester">
<portType name="pos:shippingCallbackPT"/>
</slnk:role>
</slnk:serviceLinkType>
<slnk:serviceLinkType name="schedulingLT">
<slnk:role name="schedulingService">
<slnk:portType name="pos:schedulingPT"/>
</slnk:role>
</slnk:serviceLinkType>
</definitions>
接下来定义定单服务的业务流程。在这个流程定义中有四个主要部分: - <containers> 部分定义了流程使用的数据容器,用 WSDL 消息类型来提供它们的定义。容器使流程可以根据被交换的消息保存状态数据和流程历史。
- <partners> 部分定义了在处理定单期间与业务流程交互的各方。其中的四个伙伴对应于定单的发送方(customer)、价格的提供者(invoiceProvider)、承运人(shippingProvider)和生产调度服务(schedulingProvider)。服务链接类型和角色名称描述了每个伙伴。这些信息标识了业务流程和伙伴必须提供以使该关系成功的功能,也就是购买定单流程和伙伴需要实现的 portType。
- <faultHandlers> 部分所包含的故障处理程序定义了在对调用评估和批准服务所产生的故障作出响应时必须执行的活动。在 BPEL4WS 中,无论是内部故障还是服务调用所产生的故障都由限定名称来标识。具体地说,在 BPEL4WS 中,用来标识每个 WSDL 故障的限定名称由包含相关 portType 定义和故障定义的 WSDL 文档的目标名称空间和故障的 ncname 组成。然而,值得注意的是,由于 WSDL 1.1 并不要求故障名称在操作被定义的名称空间中是唯一的,所以无法区分所有共享相同名称且被定义在相同名称空间中的故障。尽管 WSDL 有这样严重的限制,BPEL4WS 还是为故障提供了统一的命名模型,希望 WSDL 的未来版本会提供更好的故障命名模型。
- 余下的流程定义包含购买请求的正常执行的描述。在流程定义之后的部分中将解释这些描述的主要元素。
<process name="purchaseOrderProcess"
targetNamespace="http://acme.com/ws-bp/purchase"
xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
xmlns:lns="http://manufacturing.org/wsdl/purchase">
<partners>
<partner name="customer"
serviceLinkType="lns:purchaseLT"
myRole="purchaseService"/>
<partner name="invoiceProvider"
serviceLinkType="lns:invoiceLT"
myRole="invoiceRequester"
partnerRole="invoiceService"/>
<partner name="shippingProvider"
serviceLinkType="lns:shippingLT"
myRole="shippingRequester"
partnerRole="shippingService"/>
<partner name="schedulingProvider"
serviceLinkType="lns:schedulingLT"
partnerRole="schedulingService"/>
</partners>
<containers>
<container name="PO" messageType="lns:POMessage"/>
<container name="Invoice"
messageType="lns:InvMessage"/>
<container name="POFault"
messageType="lns:orderFaultType"/>
<container name="shippingRequest"
messageType="lns:shippingRequestMessage"/>
<container name="shippingInfo"
messageType="lns:shippingInfoMessage"/>
<container name="shippingSchedule"
messageType="lns:scheduleMessage"/>
</containers>
<faultHandlers>
<catch faultName="lns:cannotCompleteOrder"
faultContainer="POFault">
<reply partner="customer"
portType="lns:purchaseOrderPT"
operation="sendPurchaseOrder"
container="POFault"
faultName="cannotCompleteOrder"/>
</catch>
</faultHandlers>
<sequence>
<receive partner="customer"
portType="lns:purchaseOrderPT"
operation="sendPurchaseOrder"
container="PO">
</receive>
<flow>
<links>
<link name="ship-to-invoice"/>
<link name="ship-to-scheduling"/>
</links>
<sequence>
<assign>
<copy>
<from container="PO" part="customerInfo"/>
<to container="shippingRequest"
part="customerInfo"/>
</copy>
</assign>
<invoke partner="shippingProvider"
portType="lns:shippingPT"
operation="requestShipping"
inputContainer="shippingRequest"
outputContainer="shippingInfo">
<source linkName="ship-to-invoice"/>
</invoke>
<receive partner="shippingProvider"
portType="lns:shippingCallbackPT"
operation="sendSchedule"
container="shippingSchedule">
<source linkName="ship-to-scheduling"/>
</receive>
</sequence>
<sequence>
<invoke partner="invoiceProvider"
portType="lns:computePricePT"
operation="initiatePriceCalculation"
inputContainer="PO">
</invoke>
<invoke partner="invoiceProvider"
portType="lns:computePricePT"
operation="sendShippingPrice"
inputContainer="shippingInfo">
<target linkName="ship-to-invoice"/>
</invoke>
<receive partner="invoiceProvider"
portType="lns:invoiceCallbackPT"
operation="sendInvoice"
container="Invoice"/>
</sequence>
<sequence>
<invoke partner="schedulingProvider"
portType="lns:schedulingPT"
operation="requestProductionScheduling"
inputContainer="PO">
</invoke>
<invoke partner="schedulingProvider"
portType="lns:schedulingPT"
operation="sendShippingSchedule"
inputContainer="shippingSchedule">
<target linkName="ship-to-scheduling"/>
</invoke>
</sequence>
</flow>
<reply partner="customer"
portType="lns:purchaseOrderPT"
operation="sendPurchaseOrder"
container="Invoice"/>
</sequence>
</process>
外层 <sequence> 元素定义了主要处理部分的结构,声明了包含在其中的三个元素将按顺序被执行。先接收到客户请求(<receive> 元素),然后处理它(在启用并发执行的 <flow> 部分中),接着包含请求的最终批准状态的回复消息被返回给客户(<reply>)。请注意 <receive> 和 <reply> 元素分别和客户调用的“sendPurchaseOrder”操作的 <input> 和 <output> 消息相匹配,而在这些元素之间由流程执行的活动表示响应客户请求所执行的操作(从接收到请求之时到返回响应之时(reply))。 这个示例隐式地假设客户的请求可在较短的时间里被处理,所以要求调用者等待同步响应是合理的(因为这个服务的提供方式是请求-响应操作)。当这个假设不成立的时候,与客户的交互的更好模型是一对异步消息交换。在这种情况下,“sendPurchaseOrder”是单向操作而异步响应的发送方式是在客户“回调”接口上调用另一个单向操作。为了支持对客户的异步响应,不仅要更改“sendPurchaseOrder”的签名并定义表示客户回调接口的新的 portType,还要在前面的示例中作出两个修改。第一,表示流程-客户连接的服务链接类型“purchaseLT”需要包含第二个角色(“customer”),这个角色应列出客户回调 portType。第二,流程中的 <reply> 活动应该在客户回调操作中被 <invoke> 所取代。 在 <flow> 元素中进行的处理由三个并发运行的 <sequence> 块组成。三个并行 sequence 中的活动间的同步依赖关系由连接它们的“链接(links)”来表示。定义在 flow 中的 links 被用来把源活动连接到目标活动。(请注意每个活动通过使用嵌套的 <source> 和 <target> 元素来声明自己是链接的源还是目标。)在没有链接的情况下,直接嵌套在 flow 中的活动将被并行地执行。然而,在这个示例中的两个链接在每个 sequence 中执行的活动间引入了控制依赖关系。例如,虽然在接收到请求后可以立即开始价格计算,但是只有取得承运人信息后才能把运输价格添加到发票上;这种依赖关系由“ship-to-invoice”链接来表示,该链接把第一次调用承运人(“requestShipping”)与把运输信息发送给计价服务(“sendShippingPrice”)连接起来。类似地,只有接收到来自承运人服务的运输安排信息后才能把运输安排信息发送给生产调度服务;所以需要第二个链接(“ship-to-scheduling”)。 请注意,通过共享全局可见的数据容器,信息在不同的活动间被隐式地传递。在这个示例中,由链接表示的控制依赖关系与相应的数据依赖关系有关,承运人的价格的可用性就是一个例子,另一个例子是运输安排的可用性。通过两个全局数据容器(“shippingInfo”和“shippingSchedule”),信息从产生它的活动被传递给使用它的活动。目前的 BPEL4WS 版本仅支持全局数据容器,但未来的版本还将支持局部数据。此外,在未来的版本中,除了使用链接来表示同步依赖关系外,还将允许通过链接的数据流动。 根据操作的 WSDL 定义,某些操作可以返回故障。为了简单起见,这里假定两个操作返回相同的故障(“cannotCompleteOrder”)。当出现故障时,正常的处理被终止并把控制转移给相应的故障处理程序,故障处理程序被定义在 <faultHandlers> 部分。在这个示例中,处理程序使用 <reply> 元素来把故障返回给客户(请注意 <reply> 元素中的“faultName”属性)。 最后,请注意赋值活动是怎样被用来在数据容器间传输信息的,这一点很重要。这个示例中的简单赋值把来自源容器的消息部分传输给目标容器中的消息部分,但是也可以进行形式更为复杂的赋值。 4.2. 业务流程的结构这一节简要地总结 BPEL4WS 的语法。这一节仅提供简短的概述;本文的其它章节将详细描述每个语言构造。 该语言的基本结构是: <process name="ncname" targetNamespace="uri"
queryLanguage="anyURI"?
expressionLanguage="anyURI"?
suppressJoinFailure="yes|no"?
enableInstanceCompensation="yes|no"?
abstractProcess="yes|no"?
xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/">
<partners>?
<!-- Note: At least one role must be specified. -->
<partner name="ncname" serviceLinkType="qname"
myRole="ncname"? partnerRole="ncname"?>+
</partner>
</partners>
<containers>?
<!-- Note: The message type may be indicated with the messageType
attribute or with an inlined <wsdl:message> element within. -->
<container name="ncname" messageType="qname"?>
<wsdl:message name="ncname">?
...
</wsdl:message>
</container>
</containers>
<correlationSets>?
<correlationSet name="ncname" properties="qname-list"/>+
</correlationSets>
<faultHandlers>?
<!-- Note: There must be at least one fault handler or default. -->
<catch faultName="qname"? faultContainer="ncname"?>*
activity
</catch>
<catchAll>?
activity
</catchAll>
</faultHandlers>
<compensationHandler>?
activity
</compensationHandler>
activity
</process>
最高级别的属性如下: - queryLanguage 这个属性指定了在赋值、属性定义和其它使用中用于选择节点的 XML 查询语言。这个属性的缺省值是 XPath 1.0,其代表是 XPath 1.0 规范的 URI:http://www.w3.org/TR/1999/REC-xpath-19991116。
- expressionLanguage 这个属性指定了在流程中使用的表达式语言。这个属性的缺省值是 XPath 1.0,其代表是 XPath 1.0 规范的 URI:http://www.w3.org/TR/1999/REC-xpath-19991116。
- suppressJoinFailure 这个属性决定是否抑制流程中的所有活动的 joinFailure 故障。这个属性的缺省值是 "no"。
- enableInstanceCompensation 这个属性决定流程实例是否可被作为整体由特定于平台的方式来补偿。这个属性的缺省值是 "no"。
- abstractProcess 这个属性指定所定义的流程是抽象的(还是可执行的)。这个属性的缺省值是 "no"。
“activity”标记可以是以下任一个: - <receive>
- <reply>
- <invoke>
- <assign>
- <throw>
- <terminate>
- <wait>
- <empty>
- <sequence>
- <switch>
- <while>
- <pick>
- <flow>
- <scope>
- <compensate>
在下面的段落中将介绍以上每个元素的语法。 <receive> 构造允许业务流程阻塞等待匹配消息的到达。 <receive partner="ncname" portType="qname" operation="ncname"
container="ncname" createInstance="yes|no"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?>+
</correlations>
</receive>
<reply> 构造允许业务流程发送消息以回复通过 <receive> 接收到的消息。一个 <receive> 和一个 <reply> 组合为流程构成了在 WSDL portType 上的请求-响应操作。 <reply partner="ncname" portType="qname" operation="ncname"
container="ncname" faultName="qname"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?>+
</correlations>
</reply>
<invoke> 构造允许业务流程调用由伙伴在 portType 上提供的单向或请求-响应操作。 <invoke partner="ncname" portType="qname" operation="ncname"
inputContainer="ncname" outputContainer="ncname"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?
pattern="in|out|out-in"/>+
</correlations>
<catch faultName="qname" faultContainer="ncname"?>*
activity
</catch>
<catchAll>?
activity
</catchAll>
<compensationHandler>?
activity
</compensationHandler>
</invoke>
<assign> 构造的用途是用新的数据来更新容器的值。一个 <assign> 构造可以包括任意数量的基本赋值。赋值活动的语法是: <assign standard-attributes>
standard-elements
<copy>+
from-spec
to-spec
</copy>
</assign>
其中 from-spec 标记和 to-spec 标记的各种选项是: <from container="ncname" part="ncname"? query="queryString"?/>
<from partner="ncname" serviceReference="myRole|partnerRole"/>
<from container="ncname" property="qname"/>
<from expression="general-expr"/>
<from> ... literal value ... </from>
<from opaque="yes"/>
<to container="ncname" part="ncname"? query="queryString"?/>
<to partner="ncname"/>
<to container="ncname" property="qname"/>
<throw> 构造从业务流程中生成故障。
<throw faultName="qname" faultContainer="ncname"? standard-attributes>
standard-elements
</throw>
<terminate> 构造使您能够立即终止业务流程。
<terminate standard-attributes>
standard-elements
</terminate>
<wait> 构造允许您等待一段给定的时间或等到某一时刻。您
必须指定其中一个到期条件。
<wait (for="duration-expr" | until="deadline-expr") standard-attributes>
standard-elements
</wait>
<empty> 构造允许您在业务流程中插入“no-op”指令。例如,这个构造可被用于并行活动的同步。 <empty standard-attributes>
standard-elements
</empty>
<sequence> 构造允许您定义一组按词法顺序先后被执行的活动。 <sequence standard-attributes>
standard-elements
activity+
</sequence>
<switch> 构造允许您从一组分支中只选择一个执行分支。 <switch standard-attributes>
standard-elements
<case condition="bool-expr">+
activity
</case>
<otherwise>?
activity
</otherwise>
</switch>
<while> 构造允许您指定反复执行一个活动,直到某个成功条件被满足。 <while condition="bool-expr" standard-attributes>
standard-elements
activity
</while>
<pick> 构造允许您阻塞等待某一个合适的消息的到达或超时警报响起。当其中一个触发器触发后,相关的活动被执行,pick 也就完成了。 <pick createInstance="yes|no"? standard-attributes>
standard-elements
<onMessage partner="ncname" portType="qname"
operation="ncname" container="ncname">+
<correlations>?
<correlation set="ncname" initiation="yes|no"?>+
</correlations>
activity
</onMessage>
<onAlarm (for="duration-expr" | until="deadline-expr")>*
activity
</onAlarm>
</pick>
<flow> 构造允许您指定一个或多个被并行地执行的活动。为了定义任意
的控制结构,可以在并行的活动中使用链接。 <flow standard-attributes>
standard-elements
<links>?
<link name="ncname">+
</links>
activity+
</flow>
<scope> 构造允许您定义嵌套活动,这个嵌套活动有和自己关联的故障处理程序和补偿处理程序。 <scope containerAccessSerializable="yes|no" standard-attributes>
standard-elements
<faultHandlers>?
... see above under <process> for syntax ...
</faultHandlers>
<compensationHandler>?
... see above under <process> for syntax ...
</compensationHandler>
activity
</scope>
<compensate> 构造被用来在已正常完成执行的内层作用域上调用补偿。您只能从故障处理程序或另一个补偿处理程序中调用这个构造。 <compensate scope="ncname"? standard-attributes>
standard-elements
</compensate>
请注意上面所指的“standard-attributes”是: name="ncname"?
joinCondition="bool-expr"?
suppressJoinFailure="yes|no"?
它们的缺省值如下: - name 没有缺省值(也就是说,未命名)
- joinCondition 目标为这个活动的所有链接的活跃状态的逻辑或。
- suppressJoinFailure No
上面所指的“standard-elements”是: <target linkName="ncname"/>*
<source linkName="ncname" transitionCondition="bool-expr"?/>*
其中“transitionCondition”属性的缺省值是“true()”,这是缺省表达式语言 XPath 1.0 中的真值函数。 4.3. 语言的扩展性一般来说,BPEL4WS 所包括的构造已足够表达抽象业务流程和可执行业务流程。然而在有些情况下还是有必要通过添加
来自其它 XML 名称空间的构造来“扩展”BPEL4WS 语言。 为了支持扩展性,BPEL4WS 允许名称空间
限定的属性出现在任何 BPEL4WS 元素上,也允许其它名称空间的元素出现在 BPEL4WS 定义的元素中。这在
BPEL4WS 的 XML Schema 规范中是允许的。 所有用于 BPEL4WS 文档的扩展名称空间必须被声明。请使用以下语法来声明扩展名称空间: <extension namespace="anyURI"/>*
扩展绝不可以改变 BPEL4WS 名称空间的任何元素或属性的语义。 4.4. 业务流程的生命周期正如在引言中所述,WSDL 所直接支持的交互模型仅仅是同步或无关的异步交互的无
状态客户机/服务器模型。构建在 WSDL 之上的 BPEL4WS 假设业务流程的所有对外交互都是通过 Web 服务
操作来进行的。但是,BPEL4WS 业务流程表示有状态的长期运行的交互,其中每个交互有起点、在生命期中已定义的行为和终点。例如,在供应链中,卖方的业务流程可以提供一个服务,这个服务通过接收输入消
息来接受购买定单从而开始交互,如果该定单可以被满足,那么这个服务就把确认消息返回给买方。后来,
这个服务可以向买方发送更多消息(例如运输通知和发票)。卖方的业务流程能记住分别来自其他类似交互的每个这样的购买定单的状态。这样做是必要的,因为买方可能与同一个卖方同时进行多个购买流程。简而言之,BPEL4WS 业务流程定义可被看作创建业务流程实例的模板。 在 BPEL4WS 中流程实例的创建总是隐
式的;接收消息的活动(也就是 receive 活动和 pick 活动)可被加上注解,以表示活动的进行将导致业务流程的新实例被创建。注解的方式是把这种活动的
createInstance 属性设置为 "yes"。当消息被这样的活动接收到后,如果该业务流程的实例还不存在,那么该业务流程的实例将被创建(请参阅提供 Web 服务操作和 Pick)。 为了被实例化,每个业务流程必须包括至少一个这样的“启动活动”。它必须是初始活动,其含义是在执行流程中,从逻辑上说,它的前面没有基本活动。 如果要使不止一个启动活动被并发地执行,那么所有这些活动必须使用至少一个相关集且必须使用相同的相关集(请参阅相关性和多个启动活动示例)。 如果仅有一个启动活动需被执行,那么相关集的使用是没有限制的。这包括有多个 onMessage 分支的 pick;每个这样的分支可以使用不同的相关集,也可以不使用相关集。 业务流程实例以下面方式中的一种方式被终止: - 当定义流程行为的活动全部完成时。在这种情况下,终止是正常的。
- 当故障到达流程的作用域而且被处理或未被处理。在这种情况下,即使故障被处理而且故障处理程序没有再次扔出任何故障,终止也被认为是异常的。对于所有异常终止的作用域都没有安装补偿处理程序。
- 当流程实例被
terminate 活动显式地终止(请参阅终止服务实例)。在这种情况下,终止是异常的。
- 如果为整个业务流程指定了补偿处理程序(请参阅补偿处理程序),那么在业务流程实例正常完成后,特定于平台的方式可以补偿业务流程实例。启用这个功能的方法是把
process 的 enableInstanceCompensation 属性设置为 "yes"。
5. 服务链接、伙伴和服务引用BPEL4WS 的很重要(可能也是最重要)的用例是描述跨企业业务交互
,在这种交互中,每个企业的业务流程通过 Web 服务接口与其它企业的流程交互。为了在这种环境中真实地
模拟业务流程的进行,一个重要的要求是模拟伙伴流程的能力。WSDL 已能在抽象级别和具体级别上描述由伙
伴提供的服务的功能。业务流程与伙伴的关系通常是对等的,这需要在服务级别上有双向的相关性。换句话说
,伙伴表示由业务流程提供的服务的消费者,同时,对于业务流程来说,伙伴又表示服务的提供者。这种
情况的典型例子是基于异步消息传递(而不是基于远程过程调用)的交互。服务链接这个概念被用来直接
模拟对等伙伴关系。为了定义与伙伴的关系的形式,服务链接定义了在交互的两个方向上用到的消息和端口类型。然而,实际的伙伴服务可以在流程中被动态的确定。为了表示描述伙伴服务所需的动态数据,BPEL4WS 定义了服务引用这个概念。 在这里有必要强调所用的服务链接概念和服务引用概念是
初步的。目前,这些与 Web 服务相关的概念还没有广泛接受的规范,我们期待着在将来出现这些概念的标
准定义。为了符合预期的未来标准,BPEL4WS 规范将被相应地更新。 5.1. 服务链接为了描述两个服务间的关系,服务链接类型
定义了关系中每个服务所扮演的“角色”并指定每个角色所提供的 portType。下面举例说明服务链接类型
声明的基本语法: <serviceLinkType name="BuyerSellerLink"
xmlns="http://schemas.xmlsoap.org/ws/2002/07/service-link/">
<role name="Buyer">
<portType name="buy:BuyerPortType"/>
</role>
<role name="Seller">
<portType name="sell:SellerPortType"/>
</role>
</serviceLinkType>
每个角色可以包括任意个 WSDL portType。 在常见的情况中,每个角色的
portType 产生于不同的名称空间。然而在有些情况下可以用来自相同名称空间的 portType 来定义
服务链接类型的两个角色。在服务间定义“回调”关系的服务链接类型就会出现后一种情况。 服务
链接类型定义可以是独立于任一个服务的 WSDL 文档的单独的构件。服务链接类型定义也可以被放在
定义 portType 的 WSDL 文档中,这些 portType 也被用来定义不同的角色。 WSDL 1.1 的扩展机制被用来把 serviceLinkType 定义为新的定义类型并且在所有的情况下都是作为 <wsdl:definitions> 元素的直接子元素被放置。这是为了支持 WSDL 目标名称空间规范
的再利用,更为重要的是,也是为了支持导入 portType 的导入机制。如果服务链接类型声明链接了两个不同服
务的 portType,那么服务链接类型声明可以被放在单独的(有自己的 targetNamespace 的)WSDL 文档中。 定义服务链接类型的语法如下: <definitions name="ncname" targetNamespace="uri"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/">
...
<slnk:serviceLinkType name="ncname">
<slnk:role name="ncname">
<slnk:portType name="qname"/>+
</slnk:role>
<slnk:role name="ncname">?
<slnk:portType name="qname"/>+
</slnk:role>
</slnk:serviceLinkType>
...
</definitions>
以上定义了服务链接类型,其名称空间是 WSDL 文档元素的“targetNamespace”属性值。正如引用所有顶层 WSDL 定义那样,通过使用 QNames 来引用标识在 <slnk:role> 中的
portType。 请注意,在有些情况下定义包含一个角色(而不是两个角色)的服务链接类型是有意义的。在这种服务链接情
形中,一个服务愿意链接任何其它服务而不对其它服务提出任何要求。 您可以在本规范中的各种业务流程示例中找到 serviceLinkType 声明的示例。 5.2. 伙伴在 BPEL4WS 中,与业务流程交互的服务被模拟成伙伴。每个伙伴由 serviceLinkType 来描述。同一个 serviceLinkType 可以描述多个伙伴。例如,某个采购流程可以在它的事务中使用多个供应商,但是对于所
有的供应商都使用相同的 serviceLinkType。 <partners>
<partner name="ncname" serviceLinkType="qname"
myRole="ncname"? partnerRole="ncname"?>+
</partner>
</partners>
每个伙伴被命名,这个名称被用于与这个伙伴的所有服务交互。这一点很重要,例如,
为了多个同时产生的同一种请求而使响应与不同的伙伴相关(请参阅调用 Web 服务操作和提供 Web 服务操作)。 属性 myRole 指出了业务流程的角色而属性 partnerRole 指出了伙伴的角色。如果 serviceLinkType 退化为仅有一个角色,那么将根据需要省略其中一个属性。 请注意,伙伴声明指定了 BPEL4WS 流程将在它的行为中使用的关系的静态形式。当这样的流程被部署和执行时,在调用伙伴的服务上的操作前必须把所有出现 partnerRole 属性的伙伴解析到实际的服务。关于伙伴服务的有关信息可被设置为业务流程部署的一部分。这超出了 BPEL4WS 的范围。然而,动态地选择和分配实际的伙伴服务也是可能的,BPEL4WS 提供了这样做的机制。从概念上说,关于伙伴服务的信息的动态内容被封装在服务引用中。事实上,因为伙伴很可能是有状态的,所以服务端点信息需用特定于实例的信息来扩展。BPEL4WS 允许隐式地出现在伙伴定义中的服务引用被动态地抽取和赋值,也允许不止一次地被设置。在下面几个段落中将描述服务引用的形式。请参阅赋值,了解用于把服务引用动态地赋给伙伴的机制。 5.3. 服务引用WSDL 严格地区分 portType 和端口。PortType 使用抽象消息来定义抽象功能。端口提供实际访问
信息,包括通信端点和(通过使用扩展元素)其它有关部署的信息(例如用于加密的公钥)。绑定使
两者连结在一起。虽然服务的用户必须静态地依赖于由 portType 定义的抽象接口,但是在通常情况下可以
动态地发现和使用包括在端口定义中的信息。 服务引用的基本用途是作为一种机制,用于服务的特
定于端口的数据的动态通信。服务引用使您能在 BPEL4WS 中动态地为某个服务类型选择提供者和调用它们
的操作。BPEL4WS 提供使消息与服务的有状态实例相关的一般机制,所以携带中立于实例间的端口信息的服务引用在多数情况下是足够的。然而,一般来说,有必要在服务引用本身中携带额外的实例标识标记。 服务引用被定义为有类型的引用,它包括服务的特定于端口的数据,还可能包括关于实例标识的标记和其它有关属性的更多数据。为了避免冗余,有关的 WSDL 模式应当被尽可能地使用。 服务引用的语法结构是: <sref:serviceReference
xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/">
<wsdl:definitions> ... </wsdl:definitions>?
<sref:service name="qname"/>
<sref:referenceProperties>?
<sref:property name="qname">+
<!-- any element content -->
</sref:property>
</sref:referenceProperties>
</sref:serviceReference>
至少来说,服务引用是 <wsdl:service> 元素的限定名,其中的元素要么被直接插入在服务引用中,要么可以假定服务引用的接收方已经知晓该元素。以下是服务引用的最简单的示例: <sref:serviceReference
xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
xmlns:ns="http://example.com/services/">
<sref:service name="ns:myService"/>
</sref:serviceReference>
如果不能假设服务可通过引用已被知晓,那么它的定义可被直接插入在服务引用中,以动态地表示 WSDL 文档的服务定义部分。 <sref:serviceReference
xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
xmlns:ns="http://example.com/services/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:definitions
targetNamespace="http://example.com/services/" ...>
<wsdl:service name="myService">
...
</wsdl:service>
</wsdl:definitions>
<sref:service name="ns:myService"/>
</sref:serviceReference>
被直接插入的 <wsdl:definitions> 元素绝不可以包括不止一个直接插入的服务定义。<wsdl:definitions> 的标准使用仅包括单个服务定义。任何其它定义的存在可能影响服务引用的可移植性。 最后,出于某些目的(例如识别一个或多个感兴趣的服务实例),服务引用可能需要更多标记。服务引用模式并不把任何某种重要性赋给这些标记。这些标记是允许出现的,以作为携带用于各种目的的元数据的简便方法。要点是该数据总是与被全局命名的属性关联(请参阅消息属性)。同样地,可以假定服务引用的接收方知道它们的语义。 <sref:serviceReference
xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
xmlns:ns="http://example.com/services/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<sref:service name="ns:myService"/>
<sref:referenceProperties>
<sref:property name="ns:instanceID">
74b9f5d0-33fb-4a81-b02b-5b760641c1d6
</sref:property>
</sref:referenceProperties>
</sref:serviceReference>
在流程的部署或执行中,BPEL4WS 流程实例中的每个伙伴被分配给独特的服务引用。 6. 消息属性6.1. 动机从概念上说,消息中的数据由两部分组成:应用程序数据和有关协议的数据,其中的协议可以是业务协议,也可以是提供更高质量的服务的基础结构协议。业务协议数据的一个示例是用于相关集的相关标记(请参阅相关性)。基础结构协议的示例有安全性、事务和可靠的消息传递协议。业务协议数据通常被嵌入在应用程序可见的消息部分中,而基础结构协议几乎总是把隐式的额外部分添加到消息类型,以表示与应用程序数据分开的协议头。这种隐式部分常常被称为消息上下文,因为它们和这些上下文有关:交互的安全上下文、事务上下文和其它类似中间件上下文。业务流程可能需要访问和处理两种有关协议的数据。消息属性这个概念被定义为命名和表示消息中不同数据元素的一般方法,无论是在应用程序可见数据中还是在消息上下文中。如果要全面考虑基础结构协议的服务描述部分,那么就有必要定义服务策略、端点属性和消息上下文等概念。这些工作超出了 BPEL4WS 的范围。在这里,为了包括由隐式部分组成的消息上下文,我们以足够通用地方式来定义消息属性,但是在本规范中,消息属性主要被用于嵌入在应用程序可见的数据中的属性,而这些应用程序可见的数据被用于业务协议和抽象业务流程的定义。 6.2. 定义属性属性定义创建了全局唯一的名称并使它与 XML Schema 类型关联。目的并不在于创建新类型。目的在于创建比该类型本身更重要的名称。例如,序列号可以是整数,但是整数类型并没有表达这种重要性,而全局命名的 sequence-number 属性能表达这种重要性。属性可以出现在消息中的任何地方(包括消息上下文)。 在 BPEL4WS 中,属性的典型用途是命名标记,以用于服务实例与消息的相关。例如,在长期运行的多方业务流程的税收部分,社会保障号可被用于标识某一个交税人。社会保障号可以出现在许多不同的消息类型中,但是在有关税收的流程的上下文中,社会保障号有某种重要性,即交税人标识。于是,通过定义一个属性,一个全局名被用于该类型的这种用法,如下面的例子所示: <definitions name="properties"
targetNamespace="http://example.com/properties.wsdl"
xmlns:tns="http://example.com/properties.wsdl"
xmlns:txtyp="http://example.com/taxTypes.xsd"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!-- define a correlation property -->
<bpws:property name="taxpayerNumber"
type="txtyp:SSN"/>
...
</wsdl:definitions>
在相关性中,有效的属性名必须有全局重要性。诸如价格、风险、响应等待时间等用于业务流程中的条件行为的属性有类似的全局和公共重要性。这些属性很有可能被映射到多个消息,所以它们应该被全局地命名,就象在相关属性的情况中那样。这种属性是必需的,尤其是在抽象流程中。 WSDL 可扩展机制被用来定义属性以使 WSDL 的目标名称空间和其它有用部分成为可用的。"http://schemas.xmlsoap.org/ws/2002/07/business-process/" 是 BPEL4WS 标准名称空间,被用来定义属性。属性定义的语法是一种新的 WSDL 定义,如下所示: <wsdl:definitions name="ncname"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/">
<bpws:property name="ncname" type="qname"/>
...
</wsdl:definitions>
用于业务协议的属性通常被嵌入在应用程序可见的消息数据中。别名这个概念被用来把全局属性映射到某个消息部分中的字段。属性名成为消息部分和位置的别名,例如,别名可被用于抽象业务流程中的表达式和赋值。 <definitions name="properties"
targetNamespace="http://example.com/properties.wsdl"
xmlns:tns="http://example.com/properties.wsdl"
xmlns:txtyp="http://example.com/taxTypes.xsd"
xmlns:txmsg="http://example.com/taxMessages.wsdl"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!-- define a correlation property -->
<bpws:property name="taxpayerNumber" type="txtype:SSN"/>
...
<bpws:propertyAlias propertyName="tns:taxpayerNumber"
messageType="txmsg:taxpayerInfo" part="identification"
query="/socialsecnumber"/>
</bpws:propertyAlias>
</definitions>
bpws:propertyAlias 把全局命名的属性 tns:taxpayerNumber 定义为消息类型 txmsg:taxpayerInfo 的 identification 部分中位置的别名。
定义 propertyAlias 的语法是: <definitions name="ncname"
...
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/">
<bpws:propertyAlias propertyName="qname"
messageType="qname" part="ncname" query="queryString"/>
...
</wsdl:definitions>
message、part 和 query 等属性的解释与复制赋值中的相应的 from-spec 中的属性的解释相同(请参阅赋值)。
7. 相关性以上提供的信息暗示被传递到业务流程服务的消息的目标是接收方的服务的 WSDL 端口。这是误解,由于有状态业务流
程的本质,业务流程被实例化以符合扩展的交互历史。所以,被发送到这样的流程的消息不仅需要被传递到正确的目标端口,还需要被传递到提供端口的业务流程的正确实例。托管流程的基础结构必须以一般的方式做到这两点,以使每个流程实现不必实现实例路由的定制机制。创建新的业务流程实例的消息是特殊情况,请参阅业务流程的生命周期。 在面向对象的世界中,这种有状态的交互需要通过对象引用,对象引用本身提供了访问具有合适的交互状态和历史的某个对象(实例)的能力。这种方式适用于紧密耦合的实现,在这种实现中,对实现的结构的依赖性是正常的。在松散耦合的 Web 服务的世界中,这种引用的使用将造成实现之间脆弱的依赖关系,这种依赖关系无法适应在每个业务伙伴那里进行的业务流程实现细节的独立演化。在这个世界中,解决的方法是依靠定义伙伴间线路层的合同的业务数据和通信协议头并尽可能地避免在实例路由中使用特定于实现的标记。 请考虑买方向卖方发送购买定单的情况,这在供应链中经常出现。假定买方与卖方有稳定的业务关系并通过静态的配置把有关购买交互的文档发送到与相关 WSDL 服务端口关联的 URL。卖方需要异步地返回对定单的确认并且这种确认必须被路由到位于买方的正确的业务流程实例。为此,显而易见的标准机制是在定单消息中携带业务标记(例如购买定单编号)并把它复制到确认中以用于相关性。该标记可以在头中的消息信封中,也可以在业务文档(购买定单)中。在这两种情况中,相关消息中的标记的确切位置和类型是固定的且与实例无关。只有标记的值才与实例相关。所以,每个消息中的相关性标记的结构和位置可以在业务流程描述中以声明的方式被表达。在下一节中描述的相关集这个 BPEL4WS 概念提供了这个功能。这种声明性的信息使遵守 BPEL4WS 的基础结构能够使用相关性标记来自动地提供实例路由。 声明性的相关性指定依赖于声明性的消息属性。属性仅仅是消息中由查询来识别的“字段”— 缺省的查询语言是 XPath 1.0。为此,必须使用 XML Schema 来描述消息部分的类型或 binding 元素。相关标记和服务引用的使用限于这样描述的消息部分。更清楚地说,这种类型的实际线路格式仍可以是非 XML 的,例如,基于不同端口类型的绑定的 EDI 平面文件。 7.1. 消息相关性在业务流程实例的生命期中,它通常与涉及它工作的伙伴进行一次或多次对话。对话可基于成熟的传输基础结构,这种基础结构通过使用某种形式的对话标识使对话中的消息相关并把它们自动地路由到正确的服务实例而无需在业务流程中注释。但是,在许多情况下,相关的对话涉及的参与者不止两个或使用轻量级传输基础结构(即把相关标记直接嵌套在被交换的应用程序数据中)。在这种情况下,常常有必要提供另外的应用程序级的机制,以使消息和对话被匹配到预定的业务流程实例。 相关形式可能相当复杂。一般来说,某一个相关标记集的使用并不跨越服务实例与伙伴(实例)间的交互,而是跨越交互的一部分。被相关的交换可以嵌套和重叠,消息可以携带几个相关标记集。例如,买方可启动与卖方的被相关的交换,启动的方法是发送购买定单(purchase order,PO)并使用嵌入在 PO 文档中的 PO 编号作为相关标记。卖方在 PO 确认中使用该 PO 编号。后来,卖方可能发送携带 PO 编号(以使它与 PO 相关)的发票,也可能携带发票编号以使今后有关支付的消息只需携带发票编号作为相关标记。这样,该发票消息携带两个不同的相关标记并参与两个重叠的被相关的交换。 为了处理相关性情况,BPEL4WS 提供了声明性机制,以指定服务实例中操作的被相关组。一组相关标记可被定义为被相关的组中被所有消息共享的一组属性。这样的一组属性被称为相关集。 相关集在业务流程的实例的作用域中被实例化。正如业务流程的实例化,相关集的实例化由特别标记的操作来触发。在当前的 BPEL4WS 版本中,在一个业务流程实例的生命期中,一个相关集只能被实例化一次。在初始化后,它的值可被认为是业务流程实例的标识的别名。 在多方业务协议中,被相关的消息交换中的每个参与流程要么是该交换的初始者,要么是该交换的跟随者。初始者流程发送启动对话的第一个消息(作为操作调用的一部分)从而定义了在标记该对话的相关集中的属性值。所有其它参与者是跟随者,它们接收到提供相关集中的属性值的进站的消息从而实例化对话中的相关集。初始者和跟随者都必须把它们相应的组中的第一个活动标记为初始化相关集的活动。 7.2. 定义和使用相关集这一节的示例几乎演示了用于每个消息传递活动(receive、reply 和 invoke)的相关性。这是因为 BPEL4WS 并不假定在消息传递中使用任何成熟的对话的传输协议。在使用这种协议的情况下,BPEL4WS 中的相关性的显式使用可被限于建立对话的连接的活动。 BPEL4WS 中的每个相关集是命名的属性组,它们一起定义了在业务协议实例中识别应用程序级别的对话的方法。一个给定的消息可以携带多个相关集。在初始化后,对于携带相关集的所有操作中的所有消息来说,业务流程实例中的相关集的属性值必须相同。如果在执行时,这个约束被违反,那么遵守本规范的实现必须抛出标准故障 bpws:correlationViolation。如果一个活动企图使用还未实例化的相关集,那么相同的故障必须被抛出。正如下面的示例所演示的那样,当使用相关集的活动把属性 initiation="yes" 应用到相关集时,相关集被实例化。 <correlationSets>?
<correlationSet name="ncname" properties="qname-list"/>+
</correlationSets>
下面是扩展的相关性示例。它先定义了四个消息属性:customerID、orderNumber、vendorID 和 invoiceNumber。所有这些属性被定义为由该文档定义的 "http://example.com/supplyCorrelation.wsdl" 名称空间的一部分。 <definitions name="properties"
targetNamespace="http://example.com/supplyCorrelation.wsdl"
xmlns:tns="http://example.com/supplyCorrelation.wsdl"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!-- define correlation properties -->
<bpws:property name="customerID" type="xsd:string"/>
<bpws:property name="orderNumber" type="xsd:int"/>
<bpws:property name="vendorID" type="xsd:string"/>
<bpws:property name="invoiceNumber" type="xsd:int"/>
</definitions>
请注意这些属性是有已知的(简单的)XML Schema 类型的全局名。它们是抽象的,其含义是它们在消息中的出现需被分开指定(请参阅消息属性)。接着,该示例定义了购买定单和发票消息并使用别名概念把抽象属性映射到由选择标识的消息数据中的字段。 <definitions name="correlatedMessages"
targetNamespace="http://example.com/supplyMessages.wsdl"
xmlns:tns="http://example.com/supplyMessages.wsdl"
xmlns:cor="http://example.com/supplyCorrelation.wsdl"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!梔efine schema types for PO and invoice information -->
<types>
<xsd:complexType name="PurchaseOrder">
<xsd:element name="CID" type="xsd:string"/>
<xsd:element name="order" type="xsd:int"/>
...
</xsd:complexType>
</types>
<types>
<xsd:complexType name="PurchaseOrderResponse">
<xsd:element name="CID" type="xsd:string"/>
<xsd:element name="order" type="xsd:int"/>
...
</xsd:complexType>
</types>
<types>
<xsd:complexType name="PurchaseOrderReject">
<xsd:element name="CID" type="xsd:string"/>
<xsd:element name="order" type="xsd:int"/>
<xsd:element name="reason" type="xsd:string"/>
...
</xsd:complexType>
</types>
<types>
<xsd:complexType name="Invoice">
<xsd:element name="VID" type="xsd:string"/>
<xsd:element name="invNum" type="xsd:int"/>
</xsd:complexType>
</types>
<message name="POMessage">
<part name="PO" type="tns:PurchaseOrder"/>
</message>
<message name="POResponse">
<part name="RSP" type="tns:PurchaseOrderResponse"/>
</message>
<message name="POReject">
<part name="RJCT" type="tns:PurchaseOrderReject"/>
</message>
<message name="InvMessage">
<part name="IVC" type="tns:Invoice"/>
</message>
<bpws:propertyAlias propertyName="cor:customerID"
messageType="tns:POMessage" part="PO"
query="/CID"/>
<bpws:propertyAlias propertyName="cor:orderNumber"
messageType="tns:POMessage" part="PO"
query="/Order"/>
<bpws:propertyAlias propertyName="cor:vendorID"
messageType="tns:InvMessage" part="IVC"
query="/VID"/>
<bpws:propertyAlias propertyName="cor:invoiceNumber"
messageType="tns:InvMessage" part="IVC"
query="/InvNum"/>
...
</definitions>
最后,所用到的 portType 被定义在不同的 WSDL 文档中。 <definitions name="purchasingPortType"
targetNamespace="http://example.com/puchasing.wsdl"
xmlns:smsg="http://example.com/supplyMessages.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<portType name="PurchasingPT">
<operation name="SyncPurchase">
<input message="smsg:POMessage"/>
<output message="smsg:POResponse"/>
<fault name="tns:RejectPO" message="smsg:POReject"/>
</operation>
<operation name="AsyncPurchase">
<input message="smsg:POMessage"/>
</operation>
</portType>
<portType name="BuyerPT">
<operation name="AsyncPurchaseResponse">
<input message="smsg:POResponse"/>
<fault name="tns:RejectPO" message="smsg:POReject"/>
</operation>
<operation name="AsyncPurchaseReject">
<input message="smsg:POReject"/>
</operation>
</portType>
</definitions>
这些属性以及它们到购买定单和发票消息的映射将都被用于下面的相关性示例。 <correlationSets
xmlns:cor="http://example.com/supplyCorrelation.wsdl">
<!-- Order numbers are particular to a customer,
this set is carried in application data -->
<correlationSet name="PurchaseOrder"
properties="cor:customerID cor:orderNumber"/>
<!-- Invoice numbers are particular to a vendor,
this set is carried in application data -->
<correlationSet name="Invoice"
properties="cor:vendorID cor:invoiceNumber"/>
</correlationSets>
相关集被用于 invoke、receive 和 reply 等活动(请参阅调用 Web 服务操作和提供 Web 服务操作)以指出哪个相关集出现在被发送和接收的消息中。initiation 属性被用来指出该集是否被初始化。当该属性被设置为 "yes" 时,使用在被发送和被接收的消息中出现的属性值来初始化该集。最后,在 invoke 中,当调用的操作是同步的请求/响应时,一个 pattern 属性被用来指出相关性是应用到出站的(请求)消息还是应用到入站的(响应)消息还是应用到两者。在这个示例的其余部分中,这些概念在相关性的使用的上下文中被更详细地说明。 一个消息可以携带一个或多个相关集的标记。在第一个示例所演示的交互中,购买定单在单向入站的请求中被接收,包括发票的确认在异步的响应中被发送。PurchaseOrder correlationSet 被用于两个活动以使异步响应可在买方处与请求相关。receive 活动初始化了 PurchaseOrder correlationSet。所以买方是初始者而接收的业务流程是这个 correlationSet 的跟随者。发送异步响应的 invoke 活动也初始化了一个新的 correlationSet Invoice。该业务流程是这个被相关的交换的初始者,买方是跟随者。所以,响应消息是两个不同对话的一部分并构成它们间的桥梁。 在下面,前缀 SP:
表示名称空间 "http://example.com/puchasing.wsdl"。 <receive partner="Buyer" portType="SP:PurchasingPT"
operation="AsyncPurchase"
container="PO">
<correlations>
<correlation set="PurchaseOrder" initiation="yes">
</correlations>
</receive>
<invoke partner="Buyer" portType="SP:BuyerPT"
operation="AsyncPurchaseResponse" inputContainer="POResponse">
<correlations>
<correlation set="PurchaseOrder" initiation="no" pattern="out">
<correlation set="Invoice" initiation="yes" pattern="out">
</correlations>
</invoke>
另外,响应可能是拒绝(例如“缺货”消息),在这种情况下终止了被 correlationSet PurchaseOrder 相关的对话而不启动与 Invoice 相关的新对话。请注意 initiation 属性没有出现。所以它的缺省值是 "no"。 <invoke partner="Buyer" portType="SP:BuyerPT"
operation="AsyncPurchaseReject" inputContainer="POReject">
<correlations>
<correlation set="PurchaseOrder" pattern="out">
</correlations>
</invoke>
invoke 活动使用的另外的同步购买操作被用于买方的业务流程中,这演示了同步 Web 服务调用中的相关性的使用。 <invoke partner="Seller" portType="SP:PurchasingPT" operation="SyncPurchase"
inputContainer="sendPO"
outputContainer="getResponse">
<correlations>
<correlation set="PurchaseOrder" initiation="yes"
pattern="out">
<correlation set="Invoice" initiation="yes"
pattern="in">
</correlations>
<catch faultName="SP:RejectPO" faultContainer="POReject">
<!-- handle the fault -->
</catch>
</invoke>
请注意一个 invoke 由两个消息组成:一个出站的请求消息和一个进站的应答消息。可应用到每个消息的相关集必须被分开考虑,因为它们可能不同。在这种情况下,PurchaseOrder 相关性应用到初始化它的出站请求,而 Invoice 相关性应用到进站的应答并被该应答初始化。因为出站的消息初始化了 PurchaseOrder 相关性,所以买方是该相关性的初始者但不是 Invoice 相关性的跟随者,因为 Invoice 的相关属性值在买方接收的应答中被卖方设置。
8. 数据处理业务流程模拟有状态的交互。涉及的状态由接收和发送的消息以及其它有关数据(例如超时值)组成。业
务流程的状态的维护需要使用状态变量,这种状态变量被称为容器。另外,状态中的数据需被抽取并
被有意义地组合,以控制流程行为,这就需要数据表达式。最后,状态更新需要赋值概念。BPEL4WS 为 XML 数据
类型和 WSDL 消息类型提供这些功能。这方面的 XML 标准系列仍在发展中,为查询和表达式语言而使用流程级别的属性为融入未来的标准做好准备。 抽象流程与可执行流程之间的区别仅限于这两种
流程可用的数据处理功能集。可执行流程可以使用全部的数据处理和赋值功能但是不能使用不确定的值。抽
象流程只能对包含在消息属性中的值进行有限地处理但是能够使用不确定的值,以反映隐藏的私有行为的后果。在下面的几节中将指定两者的具体区别并在数据处理部分的末尾作出总结。 8.1. 表达式BPEL4WS 使用几种类型的表达式。用到的表达式种类如下(在括号中列出的是有关的使用上下文): -
值为布尔(Boolean)的表达式(过渡条件、连结条件、while 条件和 switch case)
- 值为截止期限(Deadline)的表达式(onAlarm 和 wait 的“until”属性)
- 值为持续时间(Duration)的表达式(onAlarm 和 wait 的“for”属性)
- 一般表达式(赋值)
BPEL4WS 为用于这些表达式的语言提供可扩展的机制。该语言由 process 元素的 expressionLanguage 属性来指定。遵守当前版本的 BPEL4WS 的实现必须支持使用 XPath 1.0 作为表达式语言。XPath 1.0 由 expressionLanguage 属性的缺省值来指定,即: http://www.w3.org/TR/1999/REC-xpath-19991116 对于给出的表达式语言,必须能够从容器中查询数据、抽取属性值以及在表达式中查询链接的状态。本
规范仅为 XPath 1.0 定义这些函数,我们期望其它表达式语言绑定将提供等同的功能。这一节的其余部分特定于 XPath 1.0。
为了使 XPath 1.0 表达式能访问流程中的信息,BPEL4WS 把几个扩展函数增加到 XPath 的内置函数。这些
扩展被定义在标准的 BPEL4WS 名称空间 "http://schemas.xmlsoap.org/ws/2002/07/business-process/"。前缀 "bpws:" 与这个名称空间关联。 用于 XPath 表达式的所有限定名的解析需使用表达式
所处的 BPEL4WS 文档中的当前作用域中的名称空间声明。 本规范定义了以下这些函数: bpws:getContainerData ('containerName', 'partName', 'locationPath'?)
这个函数从容器中抽取值。第一个参数命名了数据的源容器,第二个参数命名了从该容器中选择的部分,第三个可选参数(如果给出的话)提供了绝对位置路径(‘/’表示代表整个部分的文档片断的根)以标识表示该部分的文档片段中的子树的根。这个函数的返回值是包括单个节点的节点集,其中的节点表示整个部分(如果没有给出第三个参数)或基于 locationPath 的选择结果。如果给出的 locationPath 选择的节点集的节点数不是一个,那么遵守本规范的实现必须抛出标准故障 bpws:selectionFailure。 在抽象流程中用到的表达式中禁止使用 bpws:getContainerData。 bpws:getContainerProperty ('containerName', 'propertyName')
这个函数从容器中抽取全局属性值。第一个参数命名数据的源容器,第二个参数是从该容器中选择的全局属性的限定名(QName)(请参阅消息属性)。如果给出的属性不出现在该容器的消息类型的任何部分中,那么遵守本规范的实现必须抛出标准故障 bpws:selectionFailure。这个函数的返回值是包括表示该属性的单个节点的节点集。如果给出的属性定义选择的节点集的节点数不是一个,那么遵守本规范的实现必须抛出标准故障 bpws:selectionFailure。 bpws:getLinkStatus ('linkName')
这个函数返回表示链接状态的布尔值(请参阅链接语义)。如果链接状态是正的,那么返回值是 true;如果链接状态是负的,那么返回值是 false。这个函数绝不可以被用于连接条件以外的地方。linkName 参数必须是与连结条件关联的活动的进站的链接名。这些限制必须被静态地强制。 这些 BPEL4WS 定义的扩展函数可在所有的 XPath 1.0 表达式中使用。 以下几个段落将讲述用于 BPEL4WS 的 XPath 1.0 表达式的语法。 8.1.1. 布尔表达式这些表达式符合 XPath 1.0 Expr 的产生式,其运算结果是布尔值。 8.1.2. 值为截止期限的表达式这些表达式符合 XPath 1.0 Expr 的产生式,其运算结果是 XML Schema 类型 dateTime 或 date 的值。请注意,XPath 1.0 并不知晓 XML Schema。也就是说,XPath 1.0 的内置函数都不能产生或处理 dateTime 或 date 值。但是可以写一个符合 XML Schema 定义的常数(文字)并把它用作截止期限值,也可以从 dateTime 类或 date 类的容器(部分)中抽取字段并把它用作截止期限值。XPath 1.0 将把该文字看作 string 文字,但其结果可被解释为 dateTime 或 date 值的词法表示。
8.1.3. 值为持续时间的表达式这些表达式符合 XPath 1.0 Expr 的产生式,其运算结果是 XML Schema 类型 duration 的值。如上所述,XPath 1.0 并不知晓 XML Schema。 8.1.4. 一般表达式这些表达式符合 XPath 1.0 Expr 的产生式,其结果是任何 XPath 值类型(string、number 或 Boolean)。 有运算符的表达式受以下限制: - 所有数值(包括任意常数)可与相等或关系运算符(<、<=、=、!=、>= 和 >)一起用。
- 整数值(short、int、long、unsignedShort 等等)类型(包括常数)可被用于数值表达式,条件是仅进行整数算术运算。在实际中,这意味着除法是被禁止的。在 XPath 1.0 中进行这种限制是困难的,因为 XPath 1.0 缺乏对类型的完整支持。该限制应被看作意向的声明,当今后的表达式语言有了更完善的类型系统时,该限制将被强制执行。
- 在与 string 类的值(包括常数)一起使用时,只允许相等运算符(= 和 !=)。
这些限制反映了 XPath 1.0 的语法和语义。在这方面,未来的其它标准将提供更强的类型系统从而支持有更细微的差别的约束。规定这些限制的原因是 XPath 的一般表达式应被用来进行有关业务协议的计算(例如重试循环、单项产品计数等),这些计算在流程定义中必须是透明的。它们的主要用途并不是提供任意计算的。由于这个原因,数值表达式只处理整数计算,而通过表达式进行任意的 string 处理是禁止的。 8.2. 容器业务流程指定了涉及伙伴间消息交换的有状态的交互。业务流程的状态不仅包括被交换的消息,还包括用于业务逻辑和构造发送给伙伴的消息的中间数据。BPEL4WS 把所有的状态统一地看作一组消息。 容器所提供的方式可用于保存组成业务流程状态的消息。所保存的消息往往是已从伙伴那里接收到的消息或将被发送给伙伴的消息。但是 BPEL4WS 并没有提出这样的要求。容器所保存的消息可以作为用于计算的“临时变量”,这样的消息从不在伙伴间被交换。 每个容器的类型必须是 WSDL 消息类型。但是,BPEL4WS 允许消息类型被直接插入在容器声明中而不是被定义在 WSDL 文档中。提供这种方式的目的是为了避免在 WSDL 文档中乱塞用于“临时变量”的类型。containers 声明的语法如下: <containers>
<container name="ncname" messageType="qname"?>+
<wsdl:message name="ncname">?
...
</wsdl:message>
</container>
</containers>
以下是有直接插入的消息类型的 container 声明的示例: <container name="orderDetails">
<wsdl:message name="orderDetails">
<part name="processDuration" type="xsd:duration"/>
</wsdl:message>
</container>
如果在 targetNamespace 为 "http://example.com/orders" 的 WSDL 文档中声明相同的消息类型,那么可以这样声明: <container xmlns:ORD="http://example.com/orders"
name="orderDetails" messageType="ORD:orderDetails"/>
容器可被指定为 invoke、receive 和 reply 等活动的输入容器或输出容器(请参阅调用 Web 服务操作和提供 Web 服务操作)。当 invoke 操作返回故障消息时将在当前作用域中产生故障。所接收到的故障消息被用来初始化相应的故障处理程序中的故障容器(请参阅作用域和故障处理程序)。 在流程开始的时候,所有的容器都未被初始化。各种各样的方式(包括赋值和接收消息)可被用来初始化容器。属性赋值可使容器被部分初始化,或者,当容器的消息类型中的一些(但不是所有的)部分被赋值时,容器被部分初始化。使用容器中任何未被初始化的部分的企图必须导致标准故障 bpws:uninitializedContainer。遵守本规范的实现可以选择执行静态(执行前)分析,以检测和防止这种故障的出现。这样的分析是悲观的,这是有必要的,所以在有些情况下可能制止不产生故障的流程的使用(在某次使用中或在任何使用中)。 虽然抽象流程是不可执行的,但是 BPEL4WS 要求在使用消息前(例如在 Web 服务操作调用中,在把消息的容器用作 inputContainer 前),消息中的所有消息属性必须被初始化。 8.3. 赋值在业务流程中,把数据从一个容器复制到另一个容器是常见的任务。assign
活动可以把数据从一个容器复制到另一个容器,也可使用表达式来构造和插入新数据。使用表达式的主要动机是为了进行简单的计算(例如递增序列号)以用于描述业务协议行为。表达式对消息选择、属性和文字常数进行运算以产生容器属性或选择的新值。最后,这个活动还可把服务引用复制到伙伴链接,或把伙伴链接复制到服务引用。 assign 活动可包括一个或多个基本的赋值。 <assign standard-attributes>
standard-elements
<copy>+
from-spec
to-spec
</copy>
</assign>
assign 活动把类型兼容的值从源(“from-spec”)复制到目的地(“to-spec”)。from-spec 必须是以下形式中的一种(除非是在抽象流程中可用的不透明的形式): <from container="ncname" part="ncname"? query="queryString"?/>
<from partner="ncname" serviceReference="myRole|partnerRole"/>
<from container="ncname" property="qname"/>
<from expression="general-expr"/>
<from> ... literal value ... </from>
<from opaque="yes">
to-spec 必须是以下形式中的一种: <to container="ncname" part="ncname"? query="queryString"?/>
<to partner="ncname"/>
<to container="ncname" property="qname"/>
在各种形式中,container 属性提供容器名,part 属性提供该容器中一部分的名称。 在 from-spec 和 to-spec 的第一种形式中,query 的属性值是用于识别源容器部分或目标容器部分中的单个值的查询字符串。BPEL4WS 为用于这些查询的语言提供了可扩展的机制。该语言由 <process> 元素的“queryLanguage”属性来指定。遵守目前版本的 BPEL4WS 的实现必须支持把 XPath 1.0 用作查询语言。XPath 1.0 由 queryLanguage 属性的缺省值来指明,即: http://www.w3.org/TR/1999/REC-xpath-19991116 对于 XPath 1.0,查询的属性值必须是绝对的 locationPath(‘/’表示代表整个部分的文档片段的根)。它被用来标识代表该部分的文档片段中的子树的根。位置路径必须只选择一个节点。如果位置路径选择了零个节点或不止一个节点,那么遵守本规范的实现必须抛出标准故障 bpws:selectionFailure。请注意,part 和 query 属性是可选的。而且,在抽象流程中禁止使用 query 属性。 from-spec 和 to-spec 的第二种形式允许动态处理与伙伴关联的服务引用。partner 的属性值是在流程中声明的伙伴名称。在 from-spec 的第二种形式中,角色也必须被指定,这是因为流程可能需要表达对应于它自己的角色或伙伴的角色的服务引用。“myRole”的值表示关于伙伴的流程的服务引用是源而“partnerRole”的值表示伙伴的服务引用是源。在 to-spec 的第二种形式中,赋值只能对 partnerRole 进行,所以没有必要指定角色。用于伙伴式的 from/to-spec 的值类型总是服务引用(请参阅服务链接、伙伴和服务引用)。 from-spec 和 to-spec 的第三种形式允许显式地处理消息属性(请参阅消息属性)。这种属性形式对抽象流程特别有用,因为它们能够明确地定义消息中的特异数据元素是怎样被使用的。 第四种(“expression”)from-spec 形式允许流程对属性和容器进行简单的计算(例如递增序列号)。 第五种 from-spec 形式允许把给出的文字值作为源值赋给目的地。文字值的类型必须是目的地(to-spec)的类型。通过使用 XML Schema 的实例类型机制(xsi:type),文字值的类型可以可选地与值一起直接插入。 第六种 from-spec 形式(<from opaque="yes">)允许根据不确定的选择赋给不透明的值。这种形式只能出现在抽象流程(即不可执行的流程)中。在赋值的解释中,这种形式的值是从目标的 XSD 值空间中不确定地选出。它只能被用于“to-spec”指的是容器属性的赋值。目标属性的 XSD 类型必须是以下几种类型中的一种: - 该类型是从 xsd:string 派生的且受枚举的限制
- 该类型是从任何 XSD 整数类型派生的且受枚举限制或受 minExclusive 或 minInclusive 和 maxExclusive 或 maxInclusive 的组合的限制
在正常的意义下,使用不透明的值的赋值的流程显然是不可执行的。然而,使用正确类型的随机值的赋值来模拟可能的执行轨迹是可行的。 要使赋值是有效的,由 from 和 to 指定所引用的数据必须属于兼容的类型。以下几点准确地表达了这层含义: - from-spec 是容器且 to-spec 是容器。在这种情况下,两个容器必须属于相同的消息类型(如果两个消息类型的限定名是相同的,那么可以说它们是相等的)。
- 在 from 和 to 指定中,一个是容器,另一个不是。这是非法的,因为在容器的部分、容器部分的选择或服务引用与容器间无法直接地相互赋值。
- 在所有的其它情况下,源和目的地的类型是 XML Schema 类型,源值必须有与目的地关联的类型。请注意,这并不是要求与源关联的类型和与目的地关联的类型是相同的。具体地说,源类型可以是目的地类型的子类型。
如果违反了以上任何匹配的约束,遵守本规范的实现必须抛出标准故障 bpws:mismatchedAssignmentFailure。 8.3.1. 赋值的原子性在 BPEL4WS 中,赋值的一个重要特征是赋值活动是原子的。如果在赋值活动的执行过程中出现任何故障,那么目的地容器不被改变(目的地容器还是赋值活动开始时的样子)。无论在整个赋值活动中有几个赋值元素,原子性总是成立的。 8.3.2. 赋值示例该示例假定以下在名称空间“http://tempuri.org/bpws/example”中的复杂类型定义: <complexType name="address">
<sequence>
<element name="number" type="xsd:int"/>
<element name="street" type="xsd:string"/>
<element name="city" type="xsd:string"/>
<element name="phone">
<complexType>
<sequence>
<element name="areacode" type="xsd:int"/>
<element name="exchange" type="xsd:int"/>
<element name="number" type="xsd:int"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
假定在相同的目标名称空间中存在以下 WSDL 消息定义: <message name="person" xmlns:x="http://tempuri.org/bpws/example">
<part name="full-name" type="xsd:string"/>
<part name="address" type="x:address"/>
</message>
另外假定以下 BPEL4WS 容器声明: <container name="c1" messageType="x:person"/>
<container name="c2" messageType="x:person"/>
第一个示例演示了从一个容器复制到另一个容器: <assign>
<copy>
<from container="c1"/>
<to container="c2"/>
</copy>
</assign>
8.4. 抽象流程与可执行流程间的差别总结在用于抽象流程的 XPath 表达式中禁止使用 bpws:getContainerData。 在用于抽象流程的赋值中,from-spec 和 to-spec 不可以在容器部分中使用查询,也就是说,禁止使用 query 属性。 在抽象流程中,把 from-spec 的特殊不确定形式用于基于属性 opaque 的复制赋值是允许的,但在可执行流程中是禁止的。
9. 基本活动9.1. 每个活动的标准属性每个活动的可选的标准属性如下:一个名称、一个连结条件以及一个在连结故障发生时指示是否压制它的指示符。连结条件被用来指定到达一个活动的并行路径的要求。请参阅 Flow,了解有关后两个属性的详细信息。suppressJoinFailure 的缺省值是 no。 name="ncname"?
joinCondition="bool-expr"?
suppressJoinFailure="yes|no"?>
joinCondition 的属性值是本文档所指的表达式语言中的取值为布尔的表达式(请参阅表达式)。缺省表达式语言 XPath 的连结条件的缺省值是该活动的所有进站的链接的链接状态的逻辑“或”。 9.2. 每个活动的标准元素每个 BPEL4WS 活动有可选的嵌套的标准元素 <source> 和 <target>。在通过链接
建立同步关系时需要使用这些元素(请参阅 Flow)。每个链接被独立地
定义并被命名。链接名被用作 <source> 元素的 linkName 属性值。通过包括一个或多个 <source> 元素,一个活动可以把自己声明为一个或多个链接的源。每个 <source> 元素必须使用不同的链接名。类似地,通过包括一个或多个 <target> 元素,一个活动可以把自己声明为一个或多个链接的目标。与某个活动关联的每个 <source>
元素必须使用与那个活动中所有其它 <source> 元素不同的链接名。与某个活动关联的每个 <target>
元素必须使用与那个活动中所有其它 <target> 元素不同的链接名。每个 <source> 元素可以可选地指定过渡条件,用于为跟随这个指定链接而守护(请参阅 Flow)。如果过渡条件被省略,那么可以认为它存在且它的值是常数值 true。 <source linkName="ncname" transitionCondition="bool-expr"?/>*
<target linkName="ncname"/>*
9.3. 调用 Web 服务操作由伙伴提供的 Web 服务(请参阅服务链接、伙伴和服务引用)可被用来执行 BPEL4WS 业务流程中的工作。在这种服务上调用操作是基本活动。如前所述,这种操作可以是同步的请求/响应,也可以是异步的单向操作。对于这两种情况,BPEL4WS 使用相同的基本语法,但对于同步的情况还有一些更多选项。 异步调用仅指定操作的输入容器,这是因为它并不期待作为操作一部分的响应(请参阅提供 Web 服务操作)。同步调用既指定输入容器,也指定输出容器。一个或多个相关集可被指定,以使业务流程实例与位于伙伴处的有状态的服务相关(请参阅相关性)。 在同步调用的情况下,该操作可能返回 WSDL 故障消息。这将导致 BPEL4WS 故障。该活动可以在本地捕获这样的故障,在这种情况下将执行被指定的活动。如果该活动没有在本地捕获故障,那么该故障将被抛到包括该活动的作用域(请参阅作用域和故障处理程序)。 请注意,在 BPEL4WS 中,WSDL 故障由限定名来标识,该限定名由相应的 portType 的目标名称空间和故障名所组成。即使这种统一的命名机制与 WSDL 的故障命名模型不能准确地匹配,也必须遵守这种命名机制。因为 WSDL 并不要求故障名在服务操作被定义的名称空间中是唯一的,所以所有共享相同名称且被定义在相同名称空间的故障在 BPEL4WS 中是无法被区分的。在 WSDL 1.1 中,为了唯一地识别故障,有必要指定 portType 名称、操作名和故障名。这就限制了使用故障处理机制来处理调用故障的能力。这是 WSDL 故障模型的重要缺陷,未来的 WSDL 版本将改掉这种缺陷。 最后,一个活动可与用作它的补偿操作的另一个活动关联。这个补偿处理程序可被显式地调用,也可被外层作用域的缺省补偿处理程序来调用(请参阅作用域和补偿处理程序)。 从语义上说,本地的故障和/或补偿处理程序的指定等同于紧紧包括该活动并提供那些处理程序的隐式作用域的存在。这种隐式作用域的名称总是与它包括的活动的名称相同。 <invoke partner="ncname" portType="qname" operation="ncname"
inputContainer="ncname" outputContainer="ncname"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?
pattern="in|out|out-in"/>+
</correlations>
<catch faultName="qname" faultContainer="ncname"?>*
activity
</catch>
<catchAll>?
activity
</catchAll>
<compensationHandler>?
activity
</compensationHandler>
</invoke>
请参阅相关性,了解相关性语义的解释。下面的示例显示了有嵌套的补偿处理程序的调用。在本规范的许多地方还有其它示例。 <invoke partner="Seller" portType="SP:Purchasing"
operation="SyncPurchase"
inputContainer="sendPO"
outputContainer="getResponse">
<compensationHandler>
<invoke partner="Seller" portType="SP:Purchasing"
operation="CancelPurchase"
inputContainer="getResponse"
outputContainer="getConfirmation">
</compensationHandler>
</invoke>
9.4. 提供 Web 服务操作业务流程通过 receive 活动和相应的 reply 活动把服务提供给它的伙伴。receive 活动指定了它期望从哪个伙伴那里接收,还指定了它期望伙伴调用的端口类型和操作。 另外,receive 活动还在业务流程的生命周期中扮演角色。在 BPEL4WS 中,实例化业务流程的唯一方法是注解 receive 活动,把 createInstance 属性设置为 "yes"(请参阅 Pick,了解另一种方法)。该属性的缺省值是 "no"。被这样注解的 receive 活动必须是流程中的初始活动,也就是说,可能先于或同时与这种 receive 活动被执行的唯一其它基本活动必须是被类似地注解的 receive 活动。 把一组并发的初始活动的 createInstance 属性设置为 "yes" 是允许的。在这种情况下,目的是表达某种可能性,即一组所需的进站消息中的任一个都可以创建流程实例,这是因为这些消息的到达顺序是不可预测的。所有这些 receive 活动都必须使用相同的相关集(请参阅相关性)。遵守本规范的实现必须确保在携带相同相关集标记的进站消息中只有一个消息实际实例化了该业务流程(通常是第一个到达的,但这是实现相关的)。并发初始组中的其它进站消息必须被传递到已经被创建的实例中的相应的 receive 活动。 一个业务流程实例绝不可以为相同的伙伴、portType 和操作同时启用两个 receive 操作。请注意,receive 是阻塞操作,其含义是它的执行在流程实例接收到匹配的消息后才完成。因此,这里表达的约束禁止了逻辑故障,但不是竞赛条件。然而,本规范并不提供检测这种故障的静态分析算法,但是规定如果在业务流程实例的执行中相同伙伴、portType 和操作的两个 receive 操作实际上被同时启用,那么遵守本规范的实现必须抛出标准故障 bpws:conflictingReceive。为了这种约束的目的,pick 中的 onMessage 子句等同于 receive(请参阅 Pick)。 <receive partner="ncname" portType="qname" operation="ncname"
container="ncname" createInstance="yes|no"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?>+
</correlations>
</receive>
reply 活动被用来发送对先前通过 receive 活动被接受的请求的响应。这种响应仅对同步交互有意义。异步响应的发送方式总是调用伙伴的服务上的相应的单向操作。请求与相应的回复间的相关性所基于的约束是来自某个 portType 和操作的某个伙伴的多个未完成的同步请求绝不可以在执行中的任何时候是未完成的。如果在业务流程实例中这个约束被违反,那么遵守本规范的实现必须抛出标准故障 bpws:conflictingRequest。请注意,在语义上它不同于 bpws:conflictingReceive,这是因为有可能通过连续接收来自某个 portType 和操作的某个伙伴的相同请求来创建 conflictingRequest。为了这种约束的目的,pick 中的 onMessage 子句等同于 receive(请参阅 Pick)。
<reply partner="ncname" portType="qname" operation="ncname"
container="ncname" faultName="qname"?
standard-attributes>
standard-elements
<correlations>?
<correlation set="ncname" initiation="yes|no"?>+
</correlations>
</reply>
9.5. 更新容器内容容器通过赋值活动来更新,请参阅赋值。 9.6. 发出故障信号当业务流程需要显式地发出内部故障信号时可以使用 throw 活动。每个故障需要有一个全局唯一的 QName。throw 活动须为故障提供这样的名称,还可以可选地提供数据的容器,该容器提供有关故障的更多信息。故障处理程序可以使用这种数据,以分析和处理该故障并植入需被发送到其它服务的所有故障消息。 BPEL4WS 并不要求在 throw 元素中使用故障名前就定义它们。应用程序或特定于流程的故障名可被直接使用,方式是使用合适的 QName 作为 faultName 属性的值并提供有故障数据的容器(如果需要的话)。这提供了很轻量级的机制,可用于引入特定于应用程序的故障。 <throw faultName="qname" faultContainer="ncname"? standard-attributes>
standard-elements
</throw>
下面是不提供有故障数据的容器的 throw 活动的一个简单示例: <throw xmlns:FLT="http://example.com/faults" faultName="FLT:OutOfStock"/>
9.7. 终止服务实例terminate 活动可被用来立即放弃执行 terminate 活动的业务流程实例中的所有执行。所有的当前运行的活动必须尽可能快地被终止而不出现任何故障处理和补偿行为。
<terminate standard-attributes>
standard-elements
</terminate>
9.8. 等待wait 活动允许业务流程指定延迟时间的长短或等到某个截止期限(请参阅表达式,了解持续时间表达式和截止期限表达式的语法)。
<wait (for="duration-expr" | until="deadline-expr") standard-attributes>
standard-elements
</wait>
该活动的典型用途是在某一时刻调用操作(这里是一个常数,但更典型的用法是依赖于流程状态的表达式): <sequence>
<wait until="2002-12-24T18:00+01:00"/>
<invoke partner="CallServer" portType="AutomaticPhoneCall"
operation="TextToSpeech"
inputContainer="seasonalGreeting">
</invoke>
</sequence>
9.9. 不做任何事我们经常会需要使用不做任何事的活动,例如在故障需被不捕获和压制时。empty 活动被用于这个目的。它的语法是显然的,也是最简单的。 <empty standard-attributes>
standard-elements
</empty>
10. 结构化的活动结构化的活动规定了一组活动发生的顺序。它们描述了业务流程是怎样通过把它执行的基本活动组成结构而被创建的,这些结构表达了涉及业务协议的流程实例间的控制形式、数据流程、故障和外部事件的处理以及消息交换的协调。 BPEL4WS 的结构化的活动包括: - 活动间一般的顺序控制由
sequence、switch 和 while 来提供。
- 活动间的并发和同步由
flow 来提供。
- 基于外部事件的不确定的选择由
pick 来提供。
您可以用一般的方法来递归地使用结构化的活动。需理解的要点是结构化的活动可被任意地嵌套和组合。这样,类似图的控制方式和类似程序的控制方式被自由地组合在一起,这有点特别但很有吸引力,在传统上,这被认为是另一种方法而不是正规的组成功能。第一个示例中就有这种组合使用的简单示例. 需要强调的是在下文中,活动一词既指基本活动也指结构化的活动。 10.1. Sequence一个 sequence 活动包含一个或多个按顺序执行的活动,执行顺序是这些活动在 <sequence> 元素中被列出的先后顺序,即词法顺序。当 sequence 中的最后一个活动完成后,该 sequence 活动也就完成了。 <sequence standard-attributes>
standard-elements
activity+
</sequence>
例如: <sequence>
<flow>
...
</flow>
<scope>
...
</scope>
<pick>
...
</pick>
</sequence>
10.2. Switchswitch 结构化的活动以经常出现的形式支持条件行为。该活动由 case 元素定义的一个或多个条件分支的有序列表组成,后面可跟也可以不跟一个 otherwise 分支。以 switch 的 case 分支的出现顺序来考虑它们。条件是 true 的第一个分支被选择并被作为该 switch 的被执行的活动。如果有条件的分支都未被选择,那么 otherwise 分支将被选择。如果 otherwise 分支未被显式地指定,那么有 empty 活动的 otherwise 分支将被认为存在。当被选的分支中的活动完成后,switch 活动也就完成了。
<switch standard-attributes>
standard-elements
<case condition="bool-expr">+
activity
</case>
<otherwise>?
activity
</otherwise>
</switch>
例如: <switch xmlns:inventory="http://supply-chain.org/inventory"
xmlns:FLT="http://example.com/faults">
<case condition= "bpws:getContainerProperty(stockResult,level) > 100">
<flow>
<!-- perform fulfillment work -->
</flow>
</case>
<case condition="bpws:getContainerProperty(stockResult,level) >= 0">
<throw faultName="FLT:OutOfStock"
container="RestockEstimate"/>
</case>
<otherwise>
<throw faultName="FLT:ItemDiscontinued"/>
</otherwise>
</switch>
10.3. Whilewhile 活动支持指定的重复活动的反复执行。执行重复活动直到给出的布尔 while 条件不再被满足。
<while condition="bool-expr" standard-attributes>
standard-elements
activity
</while>
例如: ...
<container name="orderDetails">
<wsdl:message name="orderDetails">
<part name="numberOfItems" type="xsd:integer"/>
</wsdl:message>
</container>
...
<while condition=
"bpws:getContainerProperty(orderDetails,numberOfItems) > 100">
<scope>
...
</scope>
</while>
10.4. Pickpick 活动等待一组事件中的一个事件的发生,然后执行与发生的事件关联的活动。事件的发生往往是相互排斥的(某流程接收到接受消息,或者接收到拒绝消息,但不可能同时接收到这两个消息)。如果不止一个事件发生,那么被执行的活动的选择取决于哪个事件先发生。如果多个事件几乎同时发生,那么将出现竞赛且被执行的活动的选择取决于定时和实现。
pick 的形式是一组形式为事件/活动的分支且仅有一个分支被选择,所选的分支与最先发生的事件关联。请注意,当 pick 活动接受处理一个事件后,pick 将不再接受其它事件。可能的事件是某些消息的到达,其形式是进站的单向的或请求/响应操作的调用,或者是基于定时器的“警报”(从闹钟意义上说)。
当业务流程的实例的创建是由于接收到一组可能的消息中的一个消息而发生的时,可以使用 pick 的特殊形式。在这种情况下,pick 本身的 createInstance 属性的值是 yes(这个属性的缺省值是 no)。在这种情况下,pick 中的事件必须都是进站的消息,每一个等同于属性为 "createInstance=yes" 的 receive |