BPEL学习:基本活动

来源:互联网 发布:网站域名怎么更换 编辑:程序博客网 时间:2024/04/30 11:43

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

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


BPEL学习:结构化活动(7个)

结构化活动规定了一组活动发生的顺序。结构化活动通过将业务流程执行的基本活动整合到结构中来描述业务流程是如何被创建的,这些结构表达了业务协议中所涉及的控制模式、数据流、故障和外部事件的处理以及在流程实例之间进行消息交换的协调。
<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> 构造提供了以并行方式运行活动的能力,还提供了定义防护性链接的能力。它可以包含任意数量的活动。当流被启动后,这个流中的所有活动就都做好了运行的准备,除非这些活动具有还没有求得值的传入的链接。流定义了一组链接,这些链接的源活动和目标活动都必须嵌套在这个流中。

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

 

BPEL学习:创建一个简单的流程
客户发出一个贷款请求;请求得到处理,然后客户弄清楚贷款是否得到了批准。一开始,中间那个步骤将包括向启用 Web 服务的金融机构发送申请并将决定告诉客户。从客户的角度看,该流程将使用他的申请,然后给他发送一个应答。

建立流程:
上面的行为包括:获得消息、然后调用金融机构的 Web 服务以及最后应答客户。在 BPEL 中用 <receive>、<invoke> 和 <reply> 活动定义了这三个操作。然而,该流程需要定义这些简单的活动彼此之间的关系,以便知道如何以及何时运行这些活动。在 BPEL 中通过使用结构化活动来定义这些关系,这些结构化活动在如何运行它们包含的活动方面定义了一些限制。在这个示例中,您想让这三个操作一个接一个地发生。在 BPEL 中可以通过使用 <sequence> 活动获得这样的顺序,<sequence> 活动首先包含 <receive> 来消费消息,然后跟着是一个 <invoke> 来和金融机构交谈,最后以 <reply> 来向客户发送应答。因此,上面的云状图将包含以这个顺序进行的三个活动的流程,并且可以调用金融机构,如图 2 所示。

 

创建服务描述:使用 WSDL
BPEL 整合对所涉及的服务的 WSDL 描述依赖性很大,这是为了引用正在被交换的消息、正在被调用的操作以及这些操作所属于的 portType。在这个示例中,您将需要金融机构以及这个流程本身的描述。要考虑到金融界使用一组统一的消息来描述贷款信息,并且在清单 1 的贷款定义中定义了这些消息。

清单 1:贷款定义 WSDL(loandefinitions.wsdl)

 

<definitions targetNamespace="http://tempuri.org/services/loandefinitions"

 

              xmlns:tns="http://tempuri.org/services/loandefinitions"

 

              xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 

              xmlns="http://schemas.xmlsoap.org/wsdl/">

 

 

 

  <message name="creditInformationMessage">

 

     <part name="firstName" type="xsd:string"/>

 

     <part name="name" type="xsd:string"/>

 

     <part name="amount" type="xsd:integer"/>

 

  </message>

 

 

 

  <message name="loanRequestErrorMessage">

 

     <part name="errorCode" type="xsd:integer"/>

 

   </message>

 

 

 

 </definitions>

 


 

假定您知道有一个提供贷款批准服务的金融机构,其描述如下面清单 2 所示。该金融机构只包含单个操作“approve”,它用这个操作确定一个贷款请求的状态。该操作把有关客户的信息作为输入,然后输出一条包含应答的批准消息。在上面的 loandefinitions WSDL 中定义了输入消息的定义。

清单 2:贷款批准者 WSDL(loanapprover.wsdl)

 

<definitions targetNamespace="http://tempuri.org/services/loanapprover"

 

                       xmlns:tns="http://tempuri.org/services/loanapprover"

 

                       xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 

                       xmlns:loandef="http://tempuri.org/services/loandefinitions"

 

                       xmlns="http://schemas.xmlsoap.org/wsdl/">

 

 

 

   <import namespace="http://tempuri.org/services/loandefinitions"

 

            location="http://localhost:8080/bpws-samples/loanapproval/loandefinitions.wsdl"/>

 

 

 

   <message name="approvalMessage">

 

     <part name="accept" type="xsd:string"/>

 

   </message>

 

 

 

   <portType name="loanApprovalPT">

 

     <operation name="approve">

 

       <input message="loandef:creditInformationMessage"/>

 

       <output message="tns:approvalMessage"/>

 

       <fault name="loanProcessFault"

 

              message="loandef:loanRequestErrorMessage"/>

 

     </operation>

 

   </portType>

 

  

 

 <binding ...> ... </binding>

 

 <service name="LoanApprover">....</service>

 

 </definitions>

 


 

流程本身只是将输入消息转发到这个服务中,并将输出消息从这个服务中转发出去。因此,流程将通过引用上面的 portType 来向用户提供同一个描述。还要做的一件事情是为所使用的服务定义 serviceLinkType。serviceLinkType 最多定义两个角色,这两个角色引用的是由 serviceLinkType 链接在一起的任意两个服务提供和需要的 portType。对于这个示例来说,这个 serviceLinkType 将被用于把客户链接到流程,以及将流程链接到贷款批准者。因为流程本身和贷款批者都提供“approver”portType,所以只需要一个角色,并且它们二者都不要求用户支持另一个 portType。您为流程创建下面的清单 3 中的代码:

清单 3:贷款批准 WSDL(loan-approval.wsdl)

 

<definitions

 

       targetNamespace="http://loans.org/wsdl/loan-approval"

 

       xmlns="http://schemas.xmlsoap.org/wsdl/"

 

       xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/06/service-link/"

 

       xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 

       xmlns:lns="http://loans.org/wsdl/loan-approval"

 

       xmlns:apns="http://tempuri.org/services/loanapprover">

 

 

 

   <import namespace="http://tempuri.org/services/loanapprover"

 

           location="http://localhost:8080/bpws-samples/loanapproval/loanapprover.wsdl"/>

 

   <import namespace="http://tempuri.org/services/loandefinitions"

 

           location="http://localhost:8080/bpws-samples/loanapproval/loandefinitions.wsdl"/>

 

 

 

   <slnk:serviceLinkType name="loanApprovalLinkType">

 

     <slnk:role name="approver">

 

       <portType name="apns:loanApprovalPT"/>

 

     </slnk:role>

 

   </slnk:serviceLinkType>

 

 

 

   <service name="loanapprovalServiceBP"/>

 

 </definitions>

 


 

创建流程
创建这个流程的所有要求现在都已满足。您以 <process> 元素开始定义,包括将使流程能够引用需要的 WSDL 信息的名称空间(在这个名称空间(http://..../loandefinitions)中定义了消息定义)、贷款批准者的目标名称空间(http://.../loanapprover)以及流程自己的 WSDL 的目标名称空间(http://.../loan-approval)。流程现在可以用贷款批准者服务作为一个组件。

 

 

<process name="loanApprovalProcess"

 

            targetNamespace="http://acme.com/simpleloanprocessing"

 

            xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/"

 

            xmlns:lns="http://loans.org/wsdl/loan-approval"

 

            xmlns:loandef="http://tempuri.org/services/loandefinitions"

 

            xmlns:apns="http://tempuri.org/services/loanapprover">

 


 

下一步是声明涉及的各方。定义了已命名的伙伴,每个伙伴都有一个 WSDL serviceLinkType 表明其特征。对于这个示例来说,伙伴是客户和金融机构。伙伴的 myRole/partnerRole 属性指定了给定的 serviceLinkType 的伙伴和流程将如何交互。myRole 属性引用的是流程在 serviceLinkType 中将要扮演的角色,而 partnerRole 指定了伙伴将要扮演的角色。在下面的伙伴定义中对此进行了阐述。贷款批准流程为客户提供了 loanApprovalPT 功能,金融机构接着又为流程提供了这个功能。在上面的图 1 和 2 中可以看到这个关系。

 

 

  <partners>

 

     <partner name="customer"

 

                 serviceLinkType="lns:loanApproveLinkType"

 

                 myRole="approver"/>

 

     <partner name="approver"

 

                 serviceLinkType="lns:loanApprovalLinkType"

 

                 partnerRole="approver"/>

 

  </partners>

 


 

定义了伙伴之后,您就基本上为开始添加组成整合的活动做好了准备。我们再回头看一下您想让流程做什么。为了申请贷款,客户向流程发送一条消息,流程询问金融机构是否将接受贷款申请,然后用另一条消息(要么是接受申请的消息,要么是拒绝申请的消息)应答客户。在 BPEL 中您如何做到这一点呢?首先,您需要将传入的消息放在 BPEL 活动可以访问到它的地方。在 BPEL 中,数据被写入到数据容器中并且从数据容器进行访问,这些数据容器可以保存特定的 WSDL 消息类型的实例。

从客户伙伴和 loanApprovalPT 的定义可以很明显地看出,客户将发送一条 creditInformationMessage 类型的消息,然后得到一条 approvalMessage 类型的应答。因此,添加了下面的容器列表,这些容器在图 2 中用蓝色圆柱体表示:

 

 

  <containers>

 

     <container name="request" messageType="loandef:CreditInformationMessage"/>

 

     <container name="approvalInfo"  messageType="apns:approvalMessage"/>

 

  </containers>

 


 

与进程交互:接收、调用、应答
流程可能仅包含一个活动,在这个例子中就是 <sequence>。现在,您可以将一个 receive 活动添加到 sequence 中,这个 receive 活动可以接收客户的消息并把它保存到适当的容器中。receive 活动的定义必须包括将向活动发送它的消息的伙伴,以及伙伴将把它作为这条消息的目的地的流程的端口类型和操作。以这一信息为基础,一旦流程获得一条消息,它就搜索一个具有匹配的 partner-portType-operation 三元组的 receive 活动,然后把消息交给这个 receive 活动。为了避免混淆,BPEL4WS 规范规定在同一时间不能有多个带有相同的 partner-portType-operation 三元组的接收活动处于活动状态。随后,活动将把消息放在指定的容器中,然后结束。您开始 sequence 活动,然后将 receive 添加到其中:

 

 

  <sequence>

 

     <receive name="receive1" partner="customer"

 

                 portType="apns:loanApprovalPT"

 

                 operation="approve" container="request"

 

                 createInstance="yes">

 

     </receive>

 


 

下一步是询问启用 Web 服务的金融机构是否将接受贷款。这是用一个常规的 Web 服务调用来完成的,该调用是在流程中由 Invoke 活动定义。Invoke 活动在运行时将使用其输入容器(input container)中的消息来调用指定的 Web 服务,并将得到的应答放入到输出容器(output container)中,然后结束。请注意:将在“approver”伙伴上进行调用以执行 approve 操作。

 

 

     <invoke name="invokeapprover"

 

                partner="approver"

 

                portType="apns:loanApprovalPT"

 

                operation="approve"

 

                inputContainer="request"

 

                outputContainer="approvalInfo">

 

     </invoke>

 


 

为了使流程对客户的请求作出应答,流程使用一个 Reply 活动。一旦一个应答活动到达,将用流程所拥有的 partner-portType-operation 三元组来找出要把应答发送给谁。因此,为了应答通过 Receive 活动到达的消息,您将需要一个带有相同的三元组的 Reply 活动。在这个例子中,您想要告诉客户金融机构的决定是什么,所以在调用的输出容器中将会发现要被发送的消息:approvalInfo。完成应答之后,流程结束。您关闭了 sequence 标记和 process 标记。

   

 

     <reply name="reply" partner="customer" portType="apns:loanApprovalPT"

 

               operation="approve" container="approvalInfo">

 

     </reply>

 

  </sequence>

 

</process>

 


 
全部组合在一起

流程被部署之后就一直在等待,直到有人启动它为止。如果您稍加注意,就能看到 receive 包含了一个名为“createInstance”、被设置为真的属性。这向我们展示了进入流程的一个入口点。图 3 阐述了贷款批准流程将如何运行。

图 3. 运行贷款批准流程。
 

图注:箭头上的数字表示步骤发生的顺序。黑色信封是包含贷款请求的消息。红色信封是包含对该请求的应答的消息。

客户机向流程管理器发送了一条带有适当的三元组的消息之后,就会有一个流程实例被创建并开始运行。在给定的示例中,流程将启动 sequence,这个 sequence 接着将启动 receive。消息已经到达,所以它将被放入“request”容器中。然后将发生 invoke。在调用后得到的消息被放入到“approvalInfo”容器中后,reply 将获取这个消息并将其发送给客户,此时流程的实例结束。同一个流程的多个实例可以同时运行。当我解释更复杂的流程时,您将看到如何使用相关性(correlation)将消息路由到同一个流程的正确实例上以及如何从同一个流程的正确实例把消息路由出去。
 

原创粉丝点击