由于越来越多的公司正投身到 Web 服务的浪潮中,研究者们预测 Web 服务所提供的不仅仅是单端流程。一般来说,复杂应用程序在重要领域日益增多,越来越多的公司将 Web 服务作为复杂流程互动的一部分,WSC 正好顺应这一趋势。
WSCI 是基于 XML 的接口描述语言,它一般与 WSDL 结合在一起使用。它的目的是通过 Web 服务的力量使公司创建出反映当今动态的、持续变化的业务需求的业务流程。公司可以将他们的应用程序软件和资源作为 Web 服务,以便其它公司能够找到并将其应用到他们自己的业务流程中。创建业务处理过程不仅需要对所有组件的协作模式有一个清晰的定义,也需要一个描述标准的业务到业务(B2B)互动的方法。
下面部分说明了一个简单在线股票交易公司如何使用 Web 服务和 WSDL 发布服务,这种方法的缺点及 WSC 如何克服这些缺点。本文讨论的范围是解释 WSC,提供 WSC 的价值信息以及学习它更多的特性。
使用 Web 服务的在线交易公司
通过这个简单的股票交易例子,可以很好的解释 WSC 的要求和角色。为了简洁,我们大致概述涉及到的大多数行为。我并不是要讨论买卖股票的所有步骤,因为这不是本文的讨论范围。而是会给出一个简单的股票交易应用程序样例。下面的图 1 描述了一个使用在线 Web 应用程序进行股票买卖的简单及一步一步的业务流程。
图 1. 股票交易业务流程
实例
在线股票交易应用程序从第三方服务(例如 xmethods.net)获得股票的详细信息, 并将它提供给用户。 用户可能选他或她所感兴趣的股票,并且需要更多的详细信息。在线股票公司使用其中一个第三方提供的 Web 服务来获得详细信息。
一旦用户决定要买哪种股票,他或她就会下购买订单。在线股票应用程序通过其内部流程从股票市场买到股票。之后,在线交易应用程序需要用户确认购买订单,并且为用户强制设置确认订单超时时间。如果一分钟没有确认订单,系统则会向用户发送超时信息。
一旦订单被用户确认后,在线交易应用程序从用户帐户中扣减必要的费用。要实现这一操作,它会使用现存的一个第三方 Web 服务。使用一个 Web 服务来验证信用卡,使用第二个 Web 服务来扣减费用。 这两步都必须处理为一个逻辑工作单元(即事务),其中任何一个服务的失败都会向用户发送失败的信息。如果信用卡被成功验证,并且这些钱也成功地从用户帐户中转出, 在线股票交易应用程序就会从市场购买所需的股票数。用户可以下多个购买订单,并且每一个订单将会作为一个单独的逻辑单元来处理。
卖方的订单步骤和买方的订单步骤是相似的。用户下订单并在交货时确认。一旦确认了,在线应用程序下卖方订单,在证实用户帐单详细信息后从用户帐户划帐。
为了增加业务渠道,并与其它系统进行协作操作,在线交易公司发布了一个 买/卖 Web 服务应用程序作为 。在一个简单的 Web 服务例子中,您可以映射上面介绍的步骤到一个 WSDL 文件里。用户使用一些 Web 服务软件,例如 Microsoft VBA 编辑器,或者使用外部应用程序调用 Web 服务,从而调用 WSDL 操作来设置买方或卖方订单。以下链接地址可以说明如何在 VBA 中实现这个任务。 上面的图 1描述了业务过程之间的 WSDL 操作及图形.
WSDL 的缺点
一个定义得很好的买卖股票 Web 服务运行的前提是所有过程都是自动的,换句话说,它们彼此不分享任何状态。 但是在这种情况下,WSDL 自身解决了业务整合过程中的一些核心需求,例如:
流程顺序使用买/卖 Web 服务的消费者,能以任何顺序调用这些操作。例如,服务消费者可以在调用 placeBuyOrder 或者 placeSellOrder 操作之前调用现金转移操作。WSDL 不会禁止以任何顺序调用操作,使用 WSDL 的 Web 服务应用程序必须在上面的逻辑应用中迎合这一特点。
消息相关性相关性是发送信息给别人,期望收到回复,并在返回的消息实例中使用通用数据和发送消息实例相连(或者说,相关联)时,所涉及的一个简单理念。在业务过程的互动中,理解和描述出消息实例间的相关性是非常重要的。 WSDL 不具有关联消息实例的能力。换句话说,它不会保留这些操作的状态。 在一个典型的业务整合流程中,流程之间能分享状态以便提供一个相关联的流程。所有使用 WSDL 发布的操作都是无状态的,它在消息实例间没有相关性。
在本例中,当用户把下订单作为下一步操作时,Web 服务应用程序要求用户确认订单。用户也许决定改变股票数量或是改变购买时间。因为订单被修改了,他或她就要再次下购买订单。这种相互间来回的会话可能会发生几次,用户可能会下几次订单,或者说,用户与 Web 服务应用程序间发起多次对话。但是,使用 WSDL 的 Web 服务没有关联消息实例的能力。
工作单元(事务)为了让 Web 服务成为长信息交换的一部分,清楚地定义信息交换什么时候开始触发,什么时候考虑终止,考虑哪个部分以事务方式管理,这些问题都是很重要的。
本例中,placeBuyOrder, confirmBuyOrder 这些操作和 debit money 流程必须在一个单元中完成。Web 服务必须成功执行这三个操作,或者必须在执行前把这些操作恢复到一致状态,您不能把 WSDL 中发布的操作来进行分布式事务。在 WSDL 中,事务的范围是限制在单个的操作中,不能超越一个操作的范围。
异常处理虽然 WSDL 使用错误代码来抛出异常,但是它不能处理一些人工模型,比如检查特殊消息,声明超时异常,或者声明仅用于 Web 服务一些局部操作但不是全程服务的异常。
在互动流程中有一个合适的异常人工模型是很有必要的。本例中,如果用户确认买卖订单的时间超过一分钟,Web 服务就会发出超时异常。
上下文在业务互动流程中,在参与的流程间建立一个上下文环境来共享信息是很重要的。这些信息可能是一系列的声明、异常事件、或是事务特性。WSDL 不会为流程提供任何可以在上下文环境中处理的特征。
图 2. 使用 WSDL 的股票交易
WSC 如何提供帮助
WSC 帮助解决以上提到的基于 WSDL 及扩展功能的业务整合流程中的所有缺点。下节解释了 WSCI 如何处理这些问题:
上下文
要集成一些服务来创建复杂的业务服务,这些服务需要共享上下文环境信息。上下文元素组成一个环境以执行活动。同时,上下文元素也确保一系列的活动作为一个组来执行,这些有上下文环境信息的所有活动能共享声明、异常事件及事务属性。
上下文定义有局部属性和局部过程定义。局部属性只对在当前环境下执行的活动有效。局部过程定义指定在当前环境下实例化的过程。为了调用或产生局部过程,必须是从本地过程定义可见的上下文中。
在下面的 清单 1 中, 局部过程定义在买卖股票中有不同的上下文。如果在购买库存的过程中发生错误,它仅限于买的过程。例如,如果环境没有定义,买的过程中发生的错误会拒绝用户使用 Web 服务,而不是发送状态给 placeSellOrder 。以下给出 WSCI 定义的一部分:
清单 1. 上下文元素示例
<context>
<foreach select="ns1:arrayOfStockList/leg[position()>1]">
<process name = "PlaceBuyOrder" instantiation = "other">
<action name = "PlaceBuyOrder"
role= "tns:trader"
operation= "tns:placeBuyOrder">
</action>
</process>
</foreach>
<process name = "ConfirmBuyOrder" instantiation = "other">
<action name = "ConfirmBuyOrder"
role= "tns:trader"
operation= "tns:confirmBuyOrder" >
<correlate correlation =
"defs:buyStockCorrelation" instantiation= "true" />
</action>
<exception>
<onTimeout property =
"tns:confirmationTime"
type= "duration"
reference="tns:PlaceBuyOrder@end">
<compensate transaction = "tns:reverseBuyOrders"/>
</onTimeout>
</exception>
</process>
<process name="transferMoney" instantiation="other">
<action name = "cashTransaction"
role= "tns:trader"
operation= "tns:debitMoney" >
</action>
</process>
<exception>
<onMessage>
<action name = "reverseBuyOrders"
role= "tns:trader"
operation= "tns:cancelBuyOrder">
</action>
<fault code = "tns:creditCardTxFaultCode"/>
</onMessage>
</exception>
</context>
流程顺序
为了顺序地调用更多的微小业务流程,并在全局业务流程下将它们组合在一起, WSC 使用了接口元素顺序。如它的名称所示,它能确保系统顺序调用流程。当服务消费者要买股票时,在买的流程之前接口元素调用现金转移操作。这是通过在顺序元素中定义所有操作的顺序来完成的, 如以下清单 2 所示。
清单 2. 顺序元素示例
<sequence>
<!-- Web service Choreography Sequence -->
<operation name="placeBuyOrder">
<input message="buySellOrderRequest"/>
<output message="buySellOrderResponse"/>
</operation>
<operation name="confirmBuyOrder">
<input message="buySellOrderResponse"/>
<output message="buySellOrderResponse"/>
</operation>
<operation name="debitMoney">
<input message="creditCardDetails"/>
<output message="debitMoneyResponse"/>
</operation>
</sequence>
信息相关性
在 WSCS 中,当信息传到服务时,就暗示着可以建立实例。WSC 建立的实例可以用数据信息中的关键字识别。本例中,将 confirmBuyOrder 和 placeBuyOrder 过程建立关联是很重要的,因为每个过程都可能在之前的实例中发生. 当确认订单发送到服务消费者时,消费者可能会修改订单(例如,客户可能会因为价格改变修改数量),并再次下购买订单。这样的对话可能在服务消费者与 Web 服务单发生几次。
服务消费者可能下不只一份购买订单,也会触发不只一次对话。您必须识别每一次对话。这样就会用到 placeOrderId。提供了这种机制,服务消费者想下多少订单就能下多少,并且每次参与都是一个独立的对话。每一次对话,都会创建一个唯一的 placeOrderId。
要实现这样的功能,可以使用包含唯一 ID 的属性来定义关联元素。在这个特例中,股票代码如清单 3所示。
清单 3. 关联元素示例
<correlation name = "buysellCorrelation"
property = "tns:placeOrderId" />
工作单元
WSCI 使用事务元素为 Web 服务行为建模,并且将一组行为作为一个工作单元。Web 服务使用 WSCI 事务与其它服务通信,它要么完全执行完这些活动,要么将其存恢复到执行之前的一致状态。
在买卖股票的例子中,在线股票交易公司与第三方(例如第三方信用卡 Web 服务)提供的不同 Web 服务对话。如果发生异常事件或是不能与任一个第三方完成事务,Web 服务必须保证能回到前一个状态。这是通过使用事务元素和补偿元素来实现的。 清单 4 说明了这部分的代码.
清单 4. 事务元素示例
<transaction name = "reverseBuyOrder"= "atomic">
<compensation>
<action name = "reverseBuyOrder"= "tns:trader"=
"tns:reverseBuyOrder"/>
</compensation>
</transaction>
The transaction can be called in a compensation element when
an exception occurs as shown below:
<onTimeout property = "tns:confirmationTime"= "duration"=
"tns:PlaceBuyOrder@end">
<compensate transaction = "tns:reverseBuyOrder"/>
</onTimeout>
异常处理
在业务整合过程中,异常处理和选取适当的路由与处理正常情况一样重要。 维持,WSCI 使用了异常元素。WSCI 允许声明异常行为,由 Web 服务在编排好的点显示出来。异常行为的声明是上下文定义的一部分,并与异常进行关联,使用一些 Web 服务执行的行为以回应异常。异常是 WSCI 的建模能力,其设计的目的是为在 Web 服务编排的断点中显示的行为建模。它们不必表现出任何“技术错误”
WSCI 能抛出一些异常,它们来自于 WSDL 、信息内容或事件(例如,超时事件)的错误信息。异常发生后,与异常相关的行为被执行,从而实现当前环境终止。所以,WSCI 支持“恢复异常”的概念,它不会导致整个系统重排而停止(和 JAVA 中try/catch的概念相似)。但是,在没有异常行为定义的情况下,错误的发生会使上下文终止,提交到父上下文中。理论上说,异常处理行为在父上下文中定义,就会成为所有子上下文的默认行为,反过来说,在上下文定义中的异常处理行为可以在父上下文中使用来作异常处理。
在 清单 5中, 当用户确认订单的时间超过一分钟,应用程序就会超时。在 WSC 中,是通过超时特性来处理的。超时元素实际上是在异常事件中使用的事件元素。一分钟后,超时事件被触发,系统使用补偿元素回到上一次的 placeBuyOrder 状态。
清单 5. 异常和超时元素示例
<exception>
<onTimeout property = "tns:expiryTime"
type = "duration"
reference="tns:ReserveSeats@end">
<compensate transaction = "tns:seatReservation"/>
</onTimeout>
</exception>
图 3. 使用 WSCI 的股票交易
WSCI 的其它特点
下面表 1列出了 WSCI 的其它有用特点。要查看完整的清单,请参考 WSCI 文档。
表 1. WSCI 元素
元素名称 |
简短描述 |
示例 |
Selector |
选择器元素从消息中选择属性值。在抽取复杂的消息到一系列属性时它很有用。 |
您可以使用选择器元素从 getAllStocksResponse 消息中获取持有的总的股票数量: <selector property = "tns:stockCount" element = “tns: ArrayOfStockList xpath = “count (./StockList)" /> |
Call |
调用元素在动作间调用任意操作(例如,调用第三方 Web 服务)。这是自动进行的,如果在调用的流程里发生错误,动作也会失败。 |
如果应用程序为了审核和重新协调一致,要将所有的事务写入日志,就可以调用任意一个流程来记录: <process name = "DebitMoney" instantiation = "other"> <action name = "debitMoney" role = "tns:trader" operation = "tns:debitMoney"> </action> <call process = "auditTransactions"/> </action> </process> |
All activity |
所有活动元素与顺序活动相似,所有在其中定义的操作都会被执行,但是在这个元素中定义的活动能以任意顺序执行。 |
本例中,购买订单和从信用卡减钱操作可以用任何次序执行: <all> <operation name="confirmBuyOrder"> <input message="buySellOrderResponse"/> <output message="buySellOrderResponse"/> </operation> <operation name="debitMoney"> <input message="creditCardDetails"/> <output message="debitMoneyResponse"/> </operation> </all> |
Foreach |
在循环中执行活动,和 Java 的循环很相似。 |
为每一个在 arrayOfStocks中的股票执行 PlaceSellOrder 操作: <foreach select="ns1:arrayOfStockList/leg[position()>1]"> <process name = "PlaceSellOrder" instantiation = "other"> <action name = "PlaceSellOrder"= "tns:trader"= "tns:placeSellOrder"> </action> </process> </foreach> |
Switch |
switch 元素从基于条件的活动清单中选择一个活动。 |
条件的次序是很重要的,条件为真的首先执行。这个 Java 的 case 语句很相似: <switch> <case> <condition>tns:reverseBuyOrder</condition> <action name = "reverseBuyOrder" role = "tns:trader" operation = "tns:reverseBuyOrder"/> </case> <default> <action name = "confirmBuyOrder" role = "tns:trader" operation = "tns:confirmBuyOrder"/> </default> </switch> |
Until |
在布尔值的基础上执行所有活动。它至少执行这些活动一次,与 Java 中的 do while 语句相似。 |
<until> <condition>tns:creditCardProcessed</condition> <process name = "DebitMoney" instantiation = "other"> <action name = "debitMoney" role = "tns:trader" operation = "tns:debitMoney"> </action> </process> </until> |
While |
基于条件布尔值,要么所有活动都不执行,要么执行很多次,和 Java 中的 while 语句相似。 |
<while> <condition>tns:creditCardProcessed</condition> <process name = "DebitMoney" instantiation = "other"> <action name = "debitMoney" role = "tns:trader" operation = "tns:debitMoney"> </action> </process> </while> |
Delay |
使用指定的延迟时间后运行活动,如果在活动中发生异常,活动可能会在指定时间前完成。 |
<exception> <delay property = "tns:delayTime" type = "duration" reference="tns:delayBuyingStock"> </delay> </exception> |
Call |
这个元素实例化一个流程并且等待它执行完毕,call 元素对调用内部流程很有用。 |
<call process = “tns:audit" /> |
Spawn |
实例化一个流程但并不等待它执行完毕。 |
<Spawn process = “tns:logBuyTransaction" />
|
Join |
等待 spawned 流程的实例执行完毕。如果没有实例存在或所有实例都完成了,活动也完成了。 |
<join process = “tns:logBuyTransaction" /> |
结束语
到现在为止,还没有一个标准的方法来描述通过 Web 服务与其它服务编排互动的方式来进行的信息流交换。针对这个问题, BEA 系统、Intalio、SAP AG、以及 Sun Microsystems 开发了 WSCI 。本文中,通过一个简单的例子您已学到了 WSCI 所提供的一些基本功能。但是我只揭开了它的表面的部分,为了更深入地了解 WSCI,您也许想看看 WSCI 规范,并且使用 WSCI 来编写些简单的应用程序样例。