文章仅供大家参考,所有评论, 错误报告, 其他信息以及批评, 请邮寄到 Jeffery.Lee AT gmail.com
或者访问我的个人blog同我交流( http://ibuddie.spaces.live.com/ )。本文遵从GNU 的自由文档许可证(Free Document License)的条款,欢迎转载,如若修改、散布,请注明文章原始出处和来源。
生成可执行BPEL代码所需必要信息分析和归纳
JSSOA BPEL Designer实现具体的流程定义并生成对应的可执行BPEL代码,根据之前的架构设计并结合具体的贷款申请案例,本文将对具体的生成一个可执行的BPEL所需的信息进行归纳和总结,便于详细设计时参考。
另外,根据目前我所接触到的BPEL设计器来看,BPEL想达到非程序设计人员或者所谓的“业务分析员”也能使用的程度还有相当大的距离,虽然不断有新的IT供应商为构建BPEL流程提供了广泛的可视化设计产品,但技术上没有实质性的突破,我认为短时间内这种情况不会有大的改变。基于这种判断,本文在归纳和总结生成BPEL代码所必要信息时暂时不过多的考虑信息获取的具体实现。
BPEL代码分析
我们还是以BPEL规范中的贷款申请(Loan Approval)为例。该案例流程实现后的可执行BPEL代码如下:
targetNamespace ="http://example.com/loan-approval/"
xmlns ="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:lns ="http://example.com/loan-approval/wsdl/"
suppressJoinFailure ="yes" >
< import importType ="http://schemas.xmlsoap.org/wsdl/"
location ="loanServicePT.wsdl"
namespace ="http://example.com/loan-approval/wsdl/" />
< partnerLinks >
< partnerLink name ="customer"
partnerLinkType ="lns:loanPartnerLT"
myRole ="loanService" />
< partnerLink name ="approver"
partnerLinkType ="lns:loanApprovalLT"
partnerRole ="approver" />
< partnerLink name ="assessor"
partnerLinkType ="lns:riskAssessmentLT"
partnerRole ="assessor" />
</ partnerLinks >
< variables >
< variable name ="request"
messageType ="lns:creditInformationMessage" />
< variable name ="risk"
messageType ="lns:riskAssessmentMessage" />
< variable name ="approval"
messageType ="lns:approvalMessage" />
</ variables >
< faultHandlers >
< catch faultName ="lns:loanProcessFault"
faultVariable ="error"
faultMessageType ="lns:errorMessage" >
< reply partnerLink ="customer"
portType ="lns:loanServicePT"
operation ="request" variable ="error"
faultName ="unableToHandleRequest" />
</ catch >
</ faultHandlers >
< flow >
< links >
< link name ="receive-to-assess" />
< link name ="receive-to-approval" />
< link name ="approval-to-reply" />
< link name ="assess-to-setMessage" />
< link name ="setMessage-to-reply" />
< link name ="assess-to-approval" />
</ links >
< receive partnerLink ="customer"
portType ="lns:loanServicePT"
operation ="request"
variable ="request"
createInstance ="yes" >
< sources >
< source linkName ="receive-to-assess" >
< transitionCondition >
$request.amount < 10000
</ transitionCondition >
</ source >
< source linkName ="receive-to-approval" >
< transitionCondition >
$request.amount >= 10000
</ transitionCondition >
</ source >
</ sources >
</ receive >
< invoke partnerLink ="assessor"
portType ="lns:riskAssessmentPT"
operation ="check"
inputVariable ="request"
outputVariable ="risk" >
< targets >
< target linkName ="receive-to-assess" />
</ targets >
< sources >
< source linkName ="assess-to-setMessage" >
< transitionCondition >
$risk.level='low'
</ transitionCondition >
</ source >
< source linkName ="assess-to-approval" >
< transitionCondition >
$risk.level!='low'
</ transitionCondition >
</ source >
</ sources >
</ invoke >
< assign >
< targets >
< target linkName ="assess-to-setMessage" />
</ targets >
< sources >
< source linkName ="setMessage-to-reply" />
</ sources >
< copy >
< from >
< literal > yes </ literal >
</ from >
< to variable ="approval" part ="accept" />
</ copy >
</ assign >
< invoke partnerLink ="approver"
portType ="lns:loanApprovalPT"
operation ="approve"
inputVariable ="request"
outputVariable ="approval" >
< targets >
< target linkName ="receive-to-approval" />
< target linkName ="assess-to-approval" />
</ targets >
< sources >
< source linkName ="approval-to-reply" />
</ sources >
</ invoke >
< reply partnerLink ="customer"
portType ="lns:loanServicePT"
operation ="request"
variable ="approval" >
< targets >
< target linkName ="setMessage-to-reply" />
< target linkName ="approval-to-reply" />
</ targets >
</ reply >
</ flow >
</ process >
我们对该BPEL代码中的元素,及生成该元素所需要的必要信息逐一分析:
<process>元素
<process>元素是BPEL流程中的根元素,它使用name属性定义流程的名字,并建立与流程定义相关的命名空间,其主要属性表如下:
属性名 | 属性说明 |
name | 定义流程的名字 |
targetNamespace | 定义流程的目标空间 |
xmlns | 定义流程的名字空间 |
suppressJoinFailure | 决定是否抑制流程中的所有活动的joinFailure故障。这个属性的缺省值是 "no" |
<import>元素
<import>元素并非BPEL规范中定义的元素,而是XML Schema中定义的元素,用来向一个文档中添加多个包含不同目标命名空间的schema元素。在BPEL代码中常用来导入外部的XML Schema或者服务的WSDL定义。此外http://www.w3.org/2001/XMLSchema将作为名字空间被缺省导入。
属性名 | 属性说明 |
namespace | 定义被导入相应元素的命名空间 |
location | 定义导入文件的路径 |
importType | 定义导入文件的默认编码类型: 当导入XML Schema时,该类型必须设置http://www.w3.org/2001/XMLSchema 当导入WSDL1.1时,该类型必须被设置为http://schemas.xmlsoap.org/wsdl/ |
<partnerLinks>元素
仅作为<partnerLink>的父元素而存在,无需其他属性。
<partnerLink>元素
<partnerLink>元素partnerLink元素建立了端口类型的服务(伙伴),它将参与业务流程的执行过程。伙伴服务能担当流程的客户端,负责调用流程服务。相应地,伙伴服务也能被流程服务自身所调用。
<partnerLink>元素的内容代表了两个合作伙伴之间的通信交换(流程服务是一个合作伙伴,而其他服务室另一个合作伙伴)。依据通信的种类,流程服务的作用将会不同。因而partnerLink元素包含myRole与partnerRole属性,分别担当流程服务和伙伴服务服务提供者的角色。
也就是说,当流程服务被伙伴客户端服务调用时使用myRole属性,因为在这种情况下,流程服务担当服务提供者。partnerRole属性识别流程服务所调用的伙伴服务(使伙伴服务成为服务提供者)。
当期望的流程服务在相同的伙伴服务中同时担当服务请求者和服务提供者时,myRole和partnerRole将被同时使用。在流程服务和伙伴服务的异步通信中,伙伴服务回调中myRole表明流程服务的角色。
<partnerLink>元素还有一个<partnerLinkType>属性,对于包含在流程中的每个伙伴服务,partnerLinkType属性在流程中定义了partnerLink元素所引用的WSDL中portType元素。因此,这些结构通常都直接嵌入到每个伙伴服务的WSDL文档中。partnerLinkType结构在每个服务可以担当的角色中包含了一个role元素。同时又要和partnerLink元素的myRole和partnerRole属性相对应,partnerLinkType将包含一个或两个role子元素。WSDL文档中包含partnerLinkType定义的结构如下所示:
targetNamespace ="http://example.com/loan-approval/wsdl/"
xmlns:ens ="http://example.com/loan-approval/xsd/error-messages/"
xmlns:plnk ="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:soap ="http://schemas.xmlsoap.org/wsdl/soap/"
……………………………
……………………………
<plnk:partnerLinkType name ="loanPartnerLT" >
< plnk:role name ="loanService" portType ="tns:loanServicePT" />
</ plnk:partnerLinkType >
< plnk:partnerLinkType name ="loanApprovalLT" >
< plnk:role name ="approver" portType ="tns:loanApprovalPT" />
</ plnk:partnerLinkType >
< plnk:partnerLinkType name ="riskAssessmentLT" >
< plnk:role name ="assessor" portType ="tns:riskAssessmentPT" />
</ plnk:partnerLinkType >
</ wsdl:definitions >
<partnerLink>元素的属性表如下:
属性名 | 属性说明 |
name | 定义partnerLink元素的名字 |
partnerLinkType | 定义了partnerLink元素所引用的WSDL中portType元素,partnerLinkType通常在BPEL导入的WSDL文档中定义。 |
myRole | 表明流程服务的角色 |
partnerRole | 表明伙伴服务提供者的角色 |
注意:任何一个<partnerLink>元素必须定义myRole和partnerRole两个属性中至少一个。
<variables>元素
仅作为<variable>元素的父元素而存在,无需其他属性。
< variable >元素
BPEL流程服务通常使用variables结构存储与流程逻辑相关的状态信息。整个信息和数据集合被格式化为XSD schema类型,能够在处理过程中将变量置入其中并在以后获取。必须使用messageType、element或type这三种属性之一来定义允许赋给variable元素的数据类型。
messageType属性允许变量包含整个WSDL定义的消息,而element属性只引用XSD元素结构。Type属性也只代表XSD simpleType,如字符串或整数。通常,具有messageType属性的变量是为流程定义所处理的每个输出和输入消息定义的,该属性值来自伙伴流程定义的消息名称。
属性名 | 属性说明 |
name | 定义variable元素的名字,在同一作用域内该名字必须唯一 |
messageType | 定义variable元素的消息类型 |
< faultHandlers >元素
faultHandler类似于Java中的try-cache结构,它包含多个catch元素,每个都提供活动为特定类型的错误条件进行异常处理。故障会通过接收 WSDL定义的故障消息来生成,或者它们可以通过使用throw元素被明确触发。faultHandlers结构可以由catchAll元素构成(或终止)以提供默认的错误处理活动。无需定义其它属性。
<catch>元素
<catch>元素用来定义流程异常处理。其子元素为相应的异常处理操作。<catch>元素的属性表如下:
属性名 | 属性说明 |
faultName | 指定要处理的异常的名称 |
faultVariable | 指定用于异常数据的变量 |
faultMessageType | 指定用于异常数据的变量类型 |
注意:如果faultVariable定义的异常变量是一个XML定义的元素,则用faultElement代替faultMessageType来定义异常变量的类型。
<flow>元素
<flow>元素表明几个可以并行执行的活动。可以通过其内的<links>子元素来定义一个特定流程的执行序列,表明并行执行活动的依赖关系。只有当<flow>中包含的所有活动都完成后,该<flow>活动才算完成。<flow>元素无需定义其它属性。
<links>元素
仅作为<link>元素的父元素而存在,无需其它属性。
<link>元素
<link>元素用来表明活动的执行的依赖关系和次序。它可以描述更为复杂的活动执行顺序。我们可以利用flow指定一个或多个并行执行的活动。为了定义任意的控制结构,可以在并行的活动中使用<link>元素(链接)。
flow能进一步表达直接或间接嵌套在其中的活动之间的同步相关性,link(链接)用来表达这种同步相关性。
flow 活动出现的所有link必须在flow活动中分开定义,并通过名称进行标识。flow活动中嵌套的活动需要通过source或target属性来标明该活动为哪个链接的源或目标活动。在flow活动中,对于每一个link必须有且仅有一个活动作为它的源活动,同样有且仅有一个活动作为它的目标活动。目标活动会在源活动完成之后执行。这样flow内部的活动就可以通过活动构成一个有向图。
我们还可以在link的源上定义transition(变迁)条件,当源活动完成之后,BPEL引擎会检查变迁条件是否满足,如果link的转移条件满足目标活动就会执行。
<link>元素的属性表如下:
属性名 | 属性说明 |
name | 定义<link>元素的名字,在同一个<flow>里面不允许有重名发生。 |
<sources>元素
仅作为<source>元素的父元素而存在,无需其它属性。
<source>元素
用来表明一个源活动,每一个<source>元素都必须有一个对应的<target>元素。每个<source>元素都可以指定一个可选的<transitionCondition>子元素作为其所对应<link>的guard条件,缺省表达式语言XPath1.0中的真值。<source>元素的属性表如下:
属性名 | 属性说明 |
linkName | 表明其对应的<link>元素 |
<transitionCondition>元素
其内容为一个结果为布尔型的XPath表达式。
<targets>元素
仅作为<target>元素的父元素而存在,无需其它属性。
<target>元素
用来表明一个目标活动,每一个<target>元素都必须有一个对应的<source>元素。<target>元素的属性表如下:
属性名 | 属性说明 |
linkName | 表明其对应的<link>元素 |
<receive>元素
<receive>元素允许业务过程等待相匹配的消息到达,当消息到达时该活动才可以完成。<receive>活动从流程的外部伙伴那获取数据,并将其保存到流程变量。通常一个<receive>是一个流程的初始点,它会阻塞执行直到匹配的消息的到达。
receive和reply的组合对应着WSDL portType上定义的一个请求-响应操作。如果receive活动对应着一个单向(one-way)操作,则不能在流程中定义对应的reply活动。<receive>元素的属性表如下:
属性名 | 属性说明 |
partnerLink | 指定receive活动对应的partnerLink,该partnerLink一定包含一个myRole属性 |
portType | 指定供partner调用的portType |
operation | 指定供partner调用的operation |
variable | 指定receive活动接收消息变量 |
createInstance | 指定该receive活动是否初始化一个新的流程。缺省值为“no” |
<reply>元素
<reply>元素发送消息给伙伴来应答通过receive活动所接收到的消息。<reply>元素的相关属性表如下:
属性名 | 属性说明 |
partnerLink | 指定reply活动对应的partnerLink,该partnerLink一定包含一个myRole属性 |
portType | 指定供partner调用的portType |
operation | 指定供partner调用的operation |
variable | 指定reply活动回复的消息变量 |
<invoke>元素
<invoke>元素允许业务流程同步或异步调用由合作伙伴提供的服务,服务实现可以是单向或请求-响应操作。<Invoke>活动使用partnerLink属性来引用伙伴服务。通过portType和operation指定相应的WSDL接口和操作。
属性名 | 属性说明 |
partnerLink | 指定invoke活动对应的partnerLink |
portType | 指定调用的portType |
operation | 指定调用的operation |
inputVariable | 指定invoke活动的输入变量 |
outputVariable | 指定invoke活动的输出变量 |
<assign>元素
<assign>元素的作用是用新的数据来更新变量的值。assign活动可以包括任意数量的基本复制操作,通过定义相应的<copy>元素。<assign> 活动可以用于将数据从一个容器复制到另一个容器,也可以用于通过使用表达式构造和插入新数据。使用表达式主要是由于需要执行简单的计算(如递增序列号)而激发的,这些简单计算是描述业务协议行为所必需的。表达式对消息选择、属性和文字常量进行操作,以便为容器属性或选择产生新的值。本例中<assign>无需其它属性。
每个<assign>活动包含一个或多个<copy>元素;每个<copy>元素正好包含一个<from>元素和一个<to>元素。有各种形式的<from>元素和<to>元素,要记住的最重要的事情就是,从源(<from>)复制到目的地(<to>)的值必须类型兼容。
一种较简单的<from>形式仅用名称指定容器。当使用仅指定一个容器的源时,将复制整个消息;这意味着目的地也必须仅指定一个容器。
更复杂一点的<from>形式指定一个容器以及该容器中的一个部件。当使用这种形式时,目的地也必须指定一个容器及其中的一个部件。
第三种形式的<from>指定要用XPath进行求值的一般表达式。该表达式可以是XPath允许的任何东西,只要该表达式返回XPath值类型(字符串、数值或布尔)。当使用这种形式时,目的地必须指定一个容器及其中的一个部件。
简而言之,消息可以覆盖其他消息,消息部件可以覆盖其他消息部件。因为表达式不返回完整的消息,所以它们只被用于覆盖消息部件。
因为有必要使XPath表达式能够访问来自流程的信息,所以WS-BPEL引入了几个XPath扩展函数。在标准的 WS-BPEL名称空间中定义这些扩展函数。
<copy>元素
定义一组复制操作。包含一个或多个<from>和<to>元素。