内容


业务流程

学习 BPEL4WS,第 2 部分

创建一个简单的流程

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 业务流程

敬请期待该系列的后续内容。

此内容是该系列的一部分:业务流程

敬请期待该系列的后续内容。

为了演示怎样用 BPELWS 创建和聚集活动,我将描述一个处理贷款请求的简单示例。本文将阐述一个整合的主要方面,还将说明服务的 WSDL 描述与 BPEL4WS 流程定义有什么关系以及 BPEL4WS 流程定义如何使用它。在解释交互作用的伙伴、保存消息的容器以及和外界交互作用的活动的使用(即 <receive><reply><invoke> )的过程中,我创建了一个完整的流程。除了描述这个流程如何运行外,我还将说明如何使用可从 alphaWorks 上得到的 BPWS4J 引擎来部署和运行该流程。

在这个示例(请参见 图 1)中,客户发出一个贷款请求;请求得到处理,然后客户弄清楚贷款是否得到了批准。一开始,中间那个步骤将包括向启用 Web 服务的金融机构发送申请并将决定告诉客户。从客户的角度看,该流程将使用他的申请,然后给他发送一个应答。下图使用 BPEL4WS 概览文章中引入的云状图说明了贷款请求流程的外部视图。随着我继续这个系列教程,我将通过向处理请求的步骤增加复杂度来介绍 BPEL4WS 语言的其它方面。

图 1. 贷款批准流程的外部视图
贷款批准流程的外部视图

建立流程:

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

图 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 来向用户提供同一个描述。还要做的一件事情是为所使用的服务定义 serviceLinkTypeserviceLinkType 最多定义两个角色,这两个角色引用的是由 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 功能,金融机构接着又为流程提供了这个功能。在上面的 图 12中可以看到这个关系。

  <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)将消息路由到同一个流程的正确实例上以及如何从同一个流程的正确实例把消息路由出去。

在 BPWS4J 中运行流程

如果您想运行您刚刚创建的流程,您将需要获得可以从 alphaWorks 得到的 BPWS4J 引擎。(请参阅 参考资料)。请按照所提供的安装指导进行,不要忘记将 bpws4j-samples.war 文件放在适当的目录下,以便您的应用程序服务器可以找到它。

您在这里拥有的流程是 BPWS4J 发行版自带的贷款批准样本的一个简化版本(也是该规范中带有的一个)。您将使用那个样本中提供的贷款批准者服务,以及贷款批准者和流程本身的 WSDL(loanapproval.wsdl)。那些文件和我们的文件完全一样,除了流程的 WSDL 包含一个额外的 serviceLinkType (用于那些文件的流程使用的一个额外伙伴)之外。

请在引擎的文档中查阅有关运行 BPWS4J 样本的信息。要运行贷款批准样本,您可以完全照搬指导的前三个步骤。在关于如何使用贷款批准样本的第四步和第五步,有一些地方需要特别的更改。您要把您刚才创建的文件提供给服务,而不是将发行版所提供的 loan-approval.bpel 文件给它。

要创建您将要使用的 BPEL 文件,请把上面定义的流程(从 <process> 元素的开始到结束)剪切并粘贴到也是名为 loanapproval.bpel 的文件中,然后把它保存到其它目录下,以免覆盖样本。现在,当您按照第 4 步所述对服务进行部署时,请将文档中指定的流程的 WSDL 文件和您刚创建的 BPEL 文件提供给该服务(请参阅 参考资料以查找源代码文件)。

然后,部署 Web 页面将仅向您请求贷款批准者伙伴的 WSDL 文件。请将文档中描述的文件提供给这个页面。要想知道您是否意外地部署了引擎自带的 BPEL 文件,您可以通过检查它是否要求您提供另一个伙伴的名为贷款评估者(loan assessor)的 WSDL 来自己判断一下。如果它这样做了,那么您就把样本中的 BPEL 文件给它,而不是把我们的文件给它,然后您需要重新开始。所以,对于第 5 步,除了最后一句关于部署“assessor(评估者)”伙伴的内容的那句话之外,您可以完全按照文档所述进行。现在您已经为运行流程做好了准备。请遵循有关执行 BPWS4J 贷款批准样本的步骤。当您请求贷款的时候,您将得到一个 yesno 的应答。客户机能够处理您的 BPEL 文件是因为两个流程的入口点相同,且名称也相同。

如果您想要了解更多幕后的情况,请转到 webapps/bpws4j/WEB-INF/classes目录下的 log4j.properties 文件,取消对第 24 行的注释,第 24 行的内容如下:

log4j.logger.bpws.runtime.flow.base=DEBUG

这将向您显示您创建的每个活动何时开始运行。

DEBUG [base] Scope loanApprovalProcess is running
DEBUG [base] Sequence null is running
DEBUG [base] Receive receive1 is running
DEBUG [base] Invoke invokeapprover is running
DEBUG [base] Reply reply is running

下一次

在本文的下一部分,我将讲述更多关于 BPEL4J 语言的内容,并且通过向贷款批准示例中添加更多活动来阐述如何使用它们。为避免混淆,添加的部分将继续使该样本保持与规范和 BPWS4J 发行版中的样本较为接近。同时,您可能还想阅读已经发表的关于语言和运行时的其它文章。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=21623
ArticleTitle=业务流程: 学习 BPEL4WS,第 2 部分
publish-date=08012002