太上,不知有之;其次,親而譽之;其次,畏之;其次,侮之。 信不足焉,有不信焉。   悠兮其貴言。功成事遂,百姓皆謂:「我自然」。
          posts - 6,  comments - 1,  trackbacks - 0

          摘要

          本文為指定基于 Web 服務的業務流程行為定義了一種表示方法。這種表示方法被稱為 Web 服務的業務流程執行語言(Business Process Execution Language for Web Services)(以下簡稱為 BPEL4WS)。用 BPEL4WS 表示的流程只能通過使用 Web 服務接口來導出和導入功能。

          描述業務流程的方式有兩種。可執行業務流程可以模擬業務交互中的參與者的實際行為。相對而言,業務協議使用流程描述來指定涉及協議的每一方能相互看到的消息交換行為,但并不公開他們的內部行為。業務協議的流程描述被稱為抽象流程。BPEL4WS 應被用來模擬可執行流程和抽象流程的行為。

          BPEL4WS 提供了正式指定業務流程和業務交互協議的語言。這樣做是為了擴展 Web 服務交互模型并使它支持業務事務。BPEL4WS 所定義的可互操作的集成模型應該能夠促進在企業內和企業間的自動流程集成的擴展。

          狀態

          這里發布的是 BPEL4WS 規范的最初的公開草案。我們期待著不少擴展被增加到 BPEL4WS 的功能集(在本文的末尾將簡要地討論這些擴展)。BPEL4WS 代表了 XLANGWSFL 規范中的概念的融合。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 活動顯式地終止(請參閱終止服務實例)。在這種情況下,終止是異常的。

          • 如果為整個業務流程指定了補償處理程序(請參閱補償處理程序),那么在業務流程實例正常完成后,特定于平臺的方式可以補償業務流程實例。啟用這個功能的方法是把 processenableInstanceCompensation 屬性設置為 "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:taxpayerInfoidentification 部分中位置的別名。

          定義 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>
          

          messagepartquery 等屬性的解釋與復制賦值中的相應的 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>
          

          下面是擴展的相關性示例。它先定義了四個消息屬性:customerIDorderNumbervendorIDinvoiceNumber。所有這些屬性被定義為由該文檔定義的 "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>
          

          相關集被用于 invokereceivereply 等活動(請參閱調用 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 類型 dateTimedate 的值。請注意,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-specto-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。請注意,partquery 屬性是可選的。而且,在抽象流程中禁止使用 query 屬性。

          from-specto-spec 的第二種形式允許動態處理與伙伴關聯的服務引用。partner 的屬性值是在流程中聲明的伙伴名稱。在 from-spec 的第二種形式中,角色也必須被指定,這是因為流程可能需要表達對應于它自己的角色或伙伴的角色的服務引用。“myRole”的值表示關于伙伴的流程的服務引用是源而“partnerRole”的值表示伙伴的服務引用是源。在 to-spec 的第二種形式中,賦值只能對 partnerRole 進行,所以沒有必要指定角色。用于伙伴式的 from/to-spec 的值類型總是服務引用(請參閱服務鏈接、伙伴和服務引用)。

          from-specto-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-specto-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 的結構化的活動包括:

          • 活動間一般的順序控制由 sequenceswitchwhile 來提供。

          • 活動間的并發和同步由 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. Switch

          switch 結構化的活動以經常出現的形式支持條件行為。該活動由 case 元素定義的一個或多個條件分支的有序列表組成,后面可跟也可以不跟一個 otherwise 分支。以 switchcase 分支的出現順序來考慮它們。條件是 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. While

          while 活動支持指定的重復活動的反復執行。執行重復活動直到給出的布爾 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. Pick

          pick 活動等待一組事件中的一個事件的發生,然后執行與發生的事件關聯的活動。事件的發生往往是相互排斥的(某流程接收到接受消息,或者接收到拒絕消息,但不可能同時接收到這兩個消息)。如果不止一個事件發生,那么被執行的活動的選擇取決于哪個事件先發生。如果多個事件幾乎同時發生,那么將出現競賽且被執行的活動的選擇取決于定時和實現。

          pick 的形式是一組形式為事件/活動的分支且僅有一個分支被選擇,所選的分支與最先發生的事件關聯。請注意,當 pick 活動接受處理一個事件后,pick 將不再接受其它事件。可能的事件是某些消息的到達,其形式是進站的單向的或請求/響應操作的調用,或者是基于定時器的“警報”(從鬧鐘意義上說)。

          當業務流程的實例的創建是由于接收到一組可能的消息中的一個消息而發生的時,可以使用 pick 的特殊形式。在這種情況下,pick 本身的 createInstance 屬性的值是 yes(這個屬性的缺省值是 no)。在這種情況下,pick 中的事件必須都是進站的消息,每一個等同于屬性為 "createInstance=yes"receive。對于這種特殊情況,不允許出現警報。

          每個 pick 活動必須至少包括一個 onMessage 事件。對于 bpws:conflictingReceive 故障和 bpws:conflictingRequest 故障的出現的語義來說,啟用每個 onMessage 處理程序等同于啟用相應的 receive 活動(請參閱提供 Web 服務操作)。

            <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>
          

          當 pick 的一個分支被其關聯的事件的發生觸發且相應的活動完成后,pick 活動就完成了。下面的示例展示了 pick 的典型用法。這個 pick 活動可以出現在接受大定單的單項產品的循環中,但是啟用了完成操作,以作為另一個事件。

          <pick>
            <onMessage partner="buyer"
                          portType="orderEntry"
                          operation="inputLineItem"
                          container="lineItem">
                  <!-- activity to add line item to order -->
            </onMessage>
            <onMessage partner="buyer"
                          portType="orderEntry"
                          operation="orderComplete"
                          container="completionDetail">
                  <!-- activity to perform order completion -->
             </onMessage>
          
             <!-- set an alarm to go after 3 days and 10 hours -->
             <onAlarm for="P3DT10H">
                  <!-- handle timeout for order completion  -->
             </onAlarm>
          </pick>
          

          10.5. Flow

          flow 構造能提供并發和同步。flow 的語法是:

            <flow standard-attributes>
              standard-elements
              <links>?
                <link name="ncname">+
              </links>
              activity+
            </flow>
          

          對于嵌套在 flow 中的活動來說,standard attributesstandard elements 尤為重要,因為 standard attributes 和 standard elements 主要是為活動提供與 flow 有關的語義而存在的。

          把一組活動集中在 flow 中的最基本的語義效果是使它們能并發地執行。當 flow 中的所有活動完成時,flow 也就完成了。flow 中的一個活動的完成可能表明如果該活動的啟用條件變為 false,那么該活動不再被執行(請參閱刪除死路)。所以,flow 的最簡單用法等同于嵌套的并發構造。在下面的示例中,在 flow 被啟動后,兩個 invoke 活動立刻被并發地啟動。當 seller(賣方)和 shipper(承運人)都響應后,flow 就完成了(假定 invoke 操作是同步請求/響應)。僅當 flow 完成后才調用 bank(銀行)。

            <sequence>
              <flow>
                 <invoke partner="Seller" .../>
                 <invoke partner="Shipper" .../>
              </flow>
              <invoke partner="Bank" .../>
            </sequence>
          

          更為廣義地說,flow 活動創建了一組直接嵌套在其中的并發活動。它能進一步表達直接或間接嵌套在其中的活動間的同步相關性。link 構造被用來表達這種同步相關性。一個 link 有一個名稱,flow 活動的所有鏈接必須在 flow 活動中被分開定義(請參閱發展方向,了解鏈接被分開定義的原因)。活動的標準的 sourcetarget 元素被用來鏈接兩個活動。鏈接的源必須指定指定鏈接名的 source 元素,鏈接的目標必須指定指定鏈接名的 target 元素。源活動也可以通過 source 元素的 transitionCondition 屬性來指定過渡條件。如果 transitionCondition 屬性被省略,那么該屬性被認為存在且它的值是 "true"。在 flow 活動中聲明的每個 link 必須在該 flow 中恰好有一個活動作為它的源而且在該 flow 中恰好有一個活動作為它的目標。link 的源和目標可以被任意深地嵌套在直接被嵌套在該 flow 中的(結構化的)活動中,但是這要受邊界跨越的限制。

          下面的示例顯示了可以跨越結構化的活動的邊界的 link。名為“CtoD”的 link 從 sequence Y 中的活動 C 開始,到直接被嵌套在外層 flow 中的活動 D 結束。另外,該示例還演示了 sequence X 的執行必須先于 sequence Y 的執行,因為 X 是名為“XtoY”的 link 的源而該 link 的目標是 sequence Y。

            <flow>
              <links>
                <link name="XtoY"/>
                <link name="CtoD"/>
              </links>
              <sequence name="X">
                 <source linkName="XtoY"/>
                 <invoke name="A" .../>
                 <invoke name="B" .../>
              </sequence>
              <sequence name"Y">
                 <target linkName="XtoY"/>
                 <receive name="C"/>
                   <source linkName="CtoD"/>
                 </receive>
                 <invoke name="E" .../>
              </sequence>
              <invoke partner="D">
                <target linkName="CtoD"/>
              </invoke>
            </flow>
          

          一般來說,在以下情況下,link 跨越了語法構造的邊界:link 的源活動被嵌套在該構造中但目標活動并不在其中,或相反,link 的目標活動被嵌套在該構造中但源活動并不在其中。

          link 絕不可以跨越 while 活動、可序列化作用域或補償處理程序的邊界(請參閱作用域)。另外,跨越故障處理程序邊界的 link 必須是出站的,也就是說,它的源活動必須在故障處理程序中,它的目標活動必須在包括與該故障處理程序關聯的作用域的作用域中。最后,link 絕不可以創建控制循環,也就是說,源活動的邏輯優先活動絕不可以是目標活動,目標活動絕不可以邏輯優先于源活動(如果從語義上說活動 B 的初始化需要活動 A 的完成,那么 A 邏輯優先于 B)。所以,由 link 創建的有向圖總是無環的。

          10.5.1. 鏈接語義

          在剩余的這部分中,源活動是 A 的鏈接將被稱為 A 的出站鏈接,目標活動是 A 的鏈接將被稱為 A 的進站鏈接。如果鏈接的源活動和目標活動分別是 Y 和 X,那么 X 同步依賴于 Y。

          每個作為鏈接目標的活動有一個與它關聯的顯式或隱式 joinCondition 屬性。甚至只有一個進站鏈接的活動也是這樣。如果沒有顯式 joinCondition,那么隱式條件要求至少一個進站鏈接狀態是正的(下面有鏈接狀態的說明)。連結條件是布爾表達式(請參閱表達式 )。活動的連結條件的表達式必須使用布爾運算符和應用到該活動的進站鏈接的 bpws:getLinkStatus 函數來構造(請參閱表達式)。

          在不考慮鏈接的情況下,業務流程、作用域和結構化的活動的語義決定了給定的活動在什么時候開始執行。例如,sequence 中的第一個活動完成后,第二個活動就可以開始執行了。定義 switch 中的分支的行為的活動的執行條件是該分支被選擇并將被執行。類似地,當 flow 開始執行后,直接嵌套在該 flow 中的活動就可以開始執行了,因為從本質上說 flow 是并發的構造。

          如果在這種意義上就緒的活動有進站鏈接,那么,要等到該活動的所有進站鏈接狀態被確定且與該活動關聯的(顯式或隱式)連結條件的值被求出,該活動才開始執行。鏈接狀態的求值的準確語義如下:

          當活動 A 完成時將執行以下步驟以確定同步鏈接對今后執行的影響:

          • 確定 A 的所有出站的鏈接狀態。該狀態要么是正的要么是負的。為了確定每個鏈接的狀態,該鏈接的 transitionCondition 值將被求出。如果求出的值是 true,那么該狀態是正的,反之則為負的。

          • 對于每個同步依賴于 A 的活動 B,檢查:
            • 在以上描述的意義下 B 已可以開始執行(除了對進站的鏈接的依賴性)。

            • B 的所有進站的鏈接狀態被確定。
          • 如果這兩個條件都是 true,那么求出 B 的連結條件的值。如果連結條件的值是 false,那么標準故障 bpws:joinFailure 被拋出,否則,開始執行活動 B。

          如果在結構化的活動 S 的執行過程中,S 的語義要求嵌套在 S 中的活動 X 不作為執行 S 的一部分被執行,那么來自 X 的所有出站鏈接的狀態被設置為負的。在 switch 活動中不被選擇的分支中的活動就是一例,還有,在因故障(包括 bpws:joinFailure)而終止處理的作用域中未完成的活動也是一個例子(請參閱作用域補償處理程序)。

          請注意,一般來說,根據有多個出站鏈接的活動的完成情況,多個目標活動將被并行地啟用;因此,這種活動常被稱為 fork 活動。

          10.5.2. 死路刪除(Dead-Path-Elimination,DPE)

          在控制流主要由鏈接網絡定義的情況下,對活動 A 的 false 連結條件的正常解釋是不應該執行 A 而不是發生故障。此外,有必要通過把負狀態賦給 A 的出站鏈接來傳播該決定的后果。通過使用活動上的屬性 suppressJoinFailure,BPEL4WS 簡化了這種語義的表達。該屬性的值為 "yes" 的后果是在該活動及其嵌套的活動中壓制 bpws:joinFailure 故障,但是把嵌套的活動中的 suppressJoinFailure 屬性設為 "no" 后將覆蓋這個后果。壓制 bpws:joinFailure 等同于由特別的缺省處理程序邏輯地捕獲該故障,該處理程序被附加到緊緊包括有那個連結條件的活動的隱式作用域。缺省處理程序的行為是 empty 活動,也就是說,處理程序壓制了故障但不作任何處理。但是,由于有連結條件的活動未被執行,根據鏈接語義的規則,它的出站鏈接被自動地賦給負狀態。所以,在 suppressJoinFailure 屬性被設為 "yes" 的活動中,連結條件的值為 false 的語義是跳過關聯活動的執行并把該活動的所有出站鏈接狀態設為負。這被稱為死路刪除,因為在有過渡條件的鏈接網絡的類似圖的解釋中,這些語義的后果是在由連續的鏈接組成的整個路徑上傳播負鏈接狀態直到遇到值為 true 的連結條件。

          請注意,緊緊包括有連結條件的活動的隱式作用域(創建的目的是壓制 bpws:joinFailure)的名稱與該活動本身的名稱完全相同。如果這是有直接插入的故障處理程序或補償處理程序的調用活動(請參閱調用 Web 服務操作),那么故障處理程序和補償處理程序的隱式作用域將與這里描述的隱式作用域合并,這樣,bpws:joinFailure 又多了一個故障處理程序。

          suppressJoinFailure 屬性的缺省值是 "no"。這是為了在簡單的用例中避免意外的行為,這里的“簡單的用例”指的是不涉及復雜圖且沒有過渡條件的鏈接被用于同步的用例。這種用例的設計者很可能沒有完全理解鏈接的語義,他們會對壓制明確定義的故障的缺省解釋的后果感到奇怪。例如,請考慮把第一個示例suppressJoinFailure 屬性設為 "yes" 并考慮這個示例的解釋。請進一步考慮 shippingProvider 的調用被包括在提供故障處理程序的作用域中(請參閱作用域故障處理程序)。如果這些調用中的一個調用發生故障,那么來自該調用的出站鏈接狀態將是負的,位于鏈接目標的(隱式)連結條件將是 false,但是產生的 bpws:joinFailure 將被隱式地壓制且目標活動將在序列中被無聲地跳過而不是引起預期的故障。

          如果需要全面壓制 bpws:joinFailure,那么容易的實現方式是在業務流程定義的根部即整個 process 元素中使用值為 "yes"suppressJoinFailure 屬性。

          10.5.3. Flow 圖的示例

          在下面的示例中,flow 活動定義了一個圖,它的節點是一些活動,這些活動的名稱是:getBuyerInformationgetSellerInformationsettleTradeconfirmBuyerconfirmSeller。定義的鏈接有:

          • 名為 buyToSettle 的鏈接從 getBuyerInformation(在嵌套在 getBuyerInformation 中的相應的 source 元素中指定)開始到 settleTrade (在嵌套在 settleTrade 中的相應的 target 元素中指定)結束。

          • 名為 sellToSettle 的鏈接從 getSellerInformation 開始到 settleTrade 結束。

          • 名為 toBuyConfirm 的鏈接從 settleTrade 開始到 confirmBuyer 結束。

          • 名為 toSellConfirm 的鏈接從 settleTrade 開始到 confirmSeller 結束。

          根據 flow 所定義的圖結構,getBuyerInformation 活動和 getSellerInformation 活動可并行地運行。在這兩個活動都被完成前不執行 settleTrade 活動。在 settleTrade 完成這兩個活動后,confirmBuyerconfirmSeller 被再次并行地執行。

          <flow suppressJoinFailure="yes">
            <links>
              <link name="buyToSettle"/>
              <link name="sellToSettle"/>
              <link name="toBuyConfirm"/>
              <link name="toSellConfirm"/>
            </links>
            <receive name="getBuyerInformation">
              <source linkName="buyToSettle"/>
             </receive>
             <receive name="getSellerInformation">
              <source linkName="sellToSettle"/>
             </receive>
             <invoke name="settleTrade" 
                     joinCondition="buyToSettle AND sellToSettle">
              <target linkName="getBuyerInformation"/>
              <target linkName="getSellerInformation"/>
              <source linkName="toBuyConfirm"/>
               <source linkName="toSellConfirm"/>
             </invoke>
            <reply name="confirmBuyer">
              <target linkName="toBuyConfirm"/>
            </reply>
            <reply name="confirmSeller">
              <target linkName="toSellConfirm"/>
            </reply> 
          </flow>
          

          10.5.4. 鏈接和結構化的活動

          鏈接可以跨越結構化的活動的邊界。在跨越時必須確保業務流程的正確行為。下面的示例將說明當鏈接的目標活動在結構化的構造中時業務流程的行為。

          下面的 flow 被用來執行活動 A、B 和 C 的 sequence。活動 B 同步依賴于該序列外的活動 X 和活動 Y,也就是說,B 是來自 X 和 Y 的鏈接的目標。沒有位于 B 的連結條件,所以隱式地假定為缺省值,即目標為 B 的鏈接狀態的析取。所以,如果至少一個進站鏈接是正狀態,那么該條件是 true。在這種情況下,根據鏈接上的過渡條件,該條件可被表示為布爾條件 P(X,B) OR P(Y,B)

          在該 flow 中,當該 flow 開始執行時,名為 S 的 sequence 和兩個 receive 活動 X 和 Y 被并發地啟動。在 S 中,在活動 A 被完成后,在確定來自 X 和 Y 的進站鏈接的狀態和求出隱式連結條件的值之前,B 無法開始執行。當活動 X 和 Y 完成執行后,B 的連結條件的值被求出。

          假設表達式 P(X,B) OR P(Y,B) 的值是 false。在這種情況下將拋出標準故障 bpws:joinFailure,因為環境屬性 suppressJoinFailure 被設置為 "no"。所以,該 flow 的執行被中斷,B 和 C 都不被執行。

          在另一方面,如果環境屬性 suppressJoinFailure 被設置為 "yes",那么 B 的執行將被跳過但將執行 C,因為與 B 關聯的隱式作用域將壓制 bpws:joinFailure

          <flow suppressJoinFailure="no">
            <links>
              <link name="XtoB"/>
              <link name="YtoB"/>
            </links>
          
            <sequence name="S">
              <receive name="A" ...>
                ...
              </receive>
              <receive name="B" ...>
                <target linkName="XtoB"/>
                <target linkName="YtoB"/>
                ...
              </receive>
              <receive name="C" ...>
                ...
              </receive>
            </sequence>
          
            <receive name="X" ...>
              <source linkName="XtoB" transitionCondition="P(X,B)"/>
              ...
            </receive>
            <receive name="Y" ...>
              <source linkName="YtoB" transitionCondition="P(Y,B)"/>
              ...
             </receive>
          </flow>
          

          最后,假定略微改寫上面的 flow:把 A、B 和 C 從 sequence 中拿出,通過鏈接把它們鏈接起來(過渡條件為常數真值 "true")。現在,B 和 C 將總被執行。因為連結條件是析取且鏈接 AtoB 的過渡條件是常數 "true",所以連結條件的值總是 "true",且與 P(X,B) 和 P(Y,B) 的值無關。

          <flow suppressJoinFailure="no">
            <links>
              <link name="AtoB"/>
              <link name="BtoC"/>
              <link name="XtoB"/>
              <link name="YtoB"/>
            </links>
            <receive name="A">
              <source linkName="AtoB"/>
             </receive>
             <receive name="B">
              <target linkName="AtoB"/>
              <target linkName="XtoB"/>
              <target linkName="YtoB"/>
              <source linkName="BtoC"/>
             </receive>
            <receive name="C">
              <target linkName="BtoC"/>
            </receive>
            <receive name="X">
              <source linkName="XtoB" transitionCondition="P(X,B)"/>
             </receive>
            <receive name="Y">
              <source linkName="YtoB" transitionCondition="P(Y,B)"/>
             </receive>
          </flow>
          

          11. 作用域

          每個活動的執行上下文由 scope(作用域)來提供。scope 可以提供故障處理程序、補償處理程序、數據容器和相關集。

          在當前的 BPEL4WS 版本中,在由整個 process 定義的全局的 scope 中只允許出現容器和相關集。請參閱未來的發展方向,了解在未來的版本中預期的更改。

          從語法上說,所有的 scope 元素是可選的,當有些 scope 元素被省略的時候,它們有缺省的語義。下面將詳細地說明 scope 的語法和語義。

          <scope containerAccessSerializable="yes|no" standard-attributes>
              standard-elements
              <faultHandlers>?
                ...
              </faultHandlers>
              <compensationHandler>?
                ...
              </compensationHandler>
              activity
            </scope>
          

          每個 scope 有一個定義它的正常行為的主要活動。該主要活動可以是一個復雜的結構化的活動,其中有任意深度的許多嵌套的活動。所有的嵌套的活動都共享該 scope。在下面的示例中,該 scope 有一個主要的 flow 活動,其中包括兩個并發的 invoke 活動。任一個 invoke 活動可以接收一種類型或多種類型的故障響應。該 scope 的故障處理程序被兩個 invoke 活動所共享,該故障處理還可被用來捕獲由可能的故障響應所引起的故障。

            <scope>
              <faultHandlers>?
                ...
              </faultHandlers>
              <flow>
                 <invoke partner="Seller" portType="Sell:Purchasing" 
                         operation="SyncPurchase" 
                         inputContainer="sendPO" 
                         outputContainer="getResponse"/>
                 <invoke partner="Shipper" 
                         portType="Ship:TransportOrders" 
                         operation="OrderShipment" 
                         inputContainer="sendShipOrder" 
                         outputContainer="shipAck"/>
              </flow>
            </scope>
          

          11.1. 業務流程中的錯誤處理

          業務流程的持續時間往往較長,它在通信中使用異步消息。它還處理后端數據庫和行業應用程序中的敏感的商業數據。在這樣的環境中的錯誤處理是困難的但對業務的正常運行卻是至關重要的。ACID 事務的使用往往限于本地的更新,這是因為在可以產生技術錯誤、商業錯誤和故障條件的業務流程實例的長期運行中,鎖和隔離無法被保持,另外還有信任問題。結果,在許多 ACID 事務被提交期間,整個業務事務可能失敗或被取消,已完成的部分工作必須被盡可能妥善地撤銷。所以,業務流程中的錯誤處理在很大程度上依賴于眾所周知的補償概念,也就是說,企圖撤消先前的活動的效果的特定于應用程序的活動,其中,“先前的活動”是正在被放棄的較大的工作單元的一部分。在有關 Sagas 的使用 [10] 和開放的嵌套事務 [11] 等領域,已經有人進行了長期的研究。BPEL4WS 提供這種補償協議的變種,即提供撤消的靈活控制的能力。為此,BPEL4WS 提供了以特定于應用程序的方式定義故障處理和補償的能力,由此產生的特征被稱為長期運行的(業務)事務(Long-Running(Business)Transactions,LRT)。

          這里描述的 LRT 概念應被完全地用于特定于平臺的實現中,理解這一點很重要。并沒有規定業務流程須跨越(或被分布于)多個供應商和平臺。在這種環境中,WS-Transaction 規范 [12] 應被用來注冊對 LRT 實現提供的撤消通知感興趣的參與者。請參閱附錄 C,了解有關基于 WS-Transaction 概念的 BPEL4WS LRT 模型的詳細信息。

          另外,這里描述的 LRT 概念完全是本地的且發生在單個業務流程實例中,理解這一點很重要。在多方參與的服務中,沒有關于一致贊成的結果的分布式協調。分布式協定的實現是超出 BPEL4WS 范圍的傳統問題,使用 WS-Transaction 規范中描述的協議可解決這個問題。我們已認識到用 BPEL4WS 來撰寫 WS-transaction 的需求。未來的發展方向將進一步闡述這個問題。

          作為 LRT 的一個示例,請考慮旅行路線的安排和實現。這可被看作個別服務預約可使用整個 LRT 的作用域中嵌套的事務的 LRT。如果路線被取消,那么預約事務必須由取消事務來補償,對應的支付事務也必須被相應地補償。對于在數據庫中的 ACID 事務,事務協調器和它們控制的資源知道所有未提交的更新和這些更新必須被撤銷的順序,它們能完全控制這樣的撤銷。在業務事務中,補償行為本身是業務邏輯和協議的一部分且必須被顯式地指定。例如,根據機票的艙位和時間,對于取消機票的預約可能有處罰或收費。如果旅行的預付款已被支付,那么在預付前必須成功地取消預定,因為可通過減少預付款來撤銷。這意味著補償操作需按原先事務的順序來運行,這在多數事務系統中并不是標準的或缺省的作法。通過使用活動作用域作為邏輯工作單元的定義,BPEL4WS 的 LRT 功能能夠滿足這些要求。

          11.2. 補償處理程序

          通過補償處理程序,作用域可以描述一部分通過應用程序定義的方式的可撤銷的行為。有補償處理程序和故障處理程序的作用域可不受約束地任意深地被嵌套。

          11.2.1. 定義補償處理程序

          在目前的 BPEL4WS 版本中,補償處理程序僅僅是補償活動的包裝,如下所示。在許多情況下,補償處理程序需要接收有關世界的當前狀態的數據并返回關于補償結果的數據。在下面的部分及未來的發展方向中將進一步討論這個問題。

            <compensationHandler>?
              activity
            </compensationHandler>
          

          調用 Web 服務操作中已講過,invoke 活動有一個特別的快捷方式,即直接插入補償處理程序而不是顯式地使用緊貼的外層作用域。例如:

            <invoke partner="Seller" portType="SP:Purchasing" 
                    operation="SyncPurchase" 
                    inputContainer="sendPO" 
                    outputContainer="getResponse">
              <correlations>
                 <correlation set="PurchaseOrder" initiation="yes" 
                              pattern="out"/>
              </correlations>
          
              <compensationHandler>
                  <invoke partner="Seller" portType="SP:Purchasing" 
                          operation="CancelPurchase" 
                          inputContainer="getResponse"
                          outputContainer="getConfirmation">
                    <correlations>
                        <correlation set="PurchaseOrder" pattern="out"/>
                    </correlations>
                  </invoke>
              </compensationHandler>
            </invoke>
          

          在這個示例中,原先的 invoke 活動買件東西,在購買需要被補償的情況下,compensationHandler 調用在同一伙伴的同一端口上的取消操作(使用對購買請求的響應作為輸入)。

          在標準的語法中(不用 invoke 的快捷方式)可以等同地表示這個示例,如下所示:

            <scope>
              <compensationHandler>
                  <invoke partner="Seller" portType="SP:Purchasing" 
                          operation="CancelPurchase" 
                          inputContainer="getResponse"
                          outputContainer="getConfirmation">
                     <correlations>
                        <correlation set="PurchaseOrder" pattern="out"/>
                     </correlations>
                  </invoke>
              </compensationHandler>
              <invoke partner="Seller" portType="SP:Purchasing" 
                      operation="SyncPurchase" 
                      inputContainer="sendPO" 
                      outputContainer="getResponse">
                 <correlations>
                    <correlation set="PurchaseOrder" initiation="yes" 
                                 pattern="out"/>
                 </correlations>
              </invoke>
            </scope>
          

          請注意,在補償被調用前,為了其它目的,容器 getResponse 可在后來被再次使用。但是補償處理程序需要對正被撤銷的 invoke 操作的具體響應。BPEL4WS 語義規定補償處理程序(如果被調用的話)將看到所有容器的凍結的快照,這些容器就如同正被補償的作用域的執行已被完成時那樣。換句話說,如果這里顯示的補償處理程序被使用,那么補償處理程序所看到并使用的 getResponse 的內容正是它所補償的 invoke 活動在完成時的內容。這也意味著補償處理程序無法更新業務流程正在使用的容器中的活躍數據。它們完全生存在快照世界中。補償處理程序(一旦被安裝后)可被看作完全獨立的操作,業務流程實例的全局狀態既不影響它也不受它的影響。它只影響外部的實體。

          期待補償活動總是不注意世界的當前狀態是不現實的。事實上,補償既影響當前狀態也受當前狀態的影響。但是,補償在運行時所處的世界的形式是難以預測的。所以,有必要使補償活動與活躍世界間的雙向交互能夠在嚴格控制的方式下進行。為此,未來的 BPEL4WS 將向補償處理程序添加輸入和輸出參數(請參閱未來的發展方向)。

          流程的生命周期已講過,如果補償處理程序是為整個業務流程而指定的,那么特定于平臺的方式可以在業務流程實例正常完成后補償它。這個功能的啟用方法是把 processenableInstanceCompensation 屬性設置為 "yes"

          11.2.2. 調用補償處理程序

          補償處理程序的調用方法是使用 compensate 活動,該活動命名了執行補償所在的作用域,也就是說,將被執行的補償處理程序的作用域。僅當作用域正常完成執行后該作用域的補償處理程序才可被調用。調用未被安裝的補償處理程序等同于 empty 活動(它是 no-op)— 這就確保了故障處理程序不必依賴于狀態來決定哪個嵌套的作用域已成功地完成。如果一個已被安裝的補償處理程序被調用的次數大于一,那么遵守本規范的實現必須拋出標準故障 bpws:repeatedCompensation

          請注意,在 invoke 活動定義了直接插入的補償處理程序的情況下,該活動的名稱是將被用于 compensate 活動的 scope 名。

            <compensate scope="ncname"? standard-attributes>
              standard-elements
            </compensate>
          

          顯式地執行 compensate 活動的能力是 BPEL4WS 的應用程序控制的錯誤處理框架的基礎所在。該活動只能被用于業務流程的以下部分中:

          • 在作用域的 fault 處理程序中,該作用域緊緊包括補償將被執行的作用域。

          • 在作用域的補償處理程序中,該作用域緊緊包括補償將被執行的作用域。

          例如:

          <compensate scope="RecordPayment"/>
          

          如果按名稱被顯式地補償的作用域在循環中被執行,那么在后續的迭代中補償處理程序的實例將按相反的順序被執行。

          如果作用域沒有補償處理程序,那么缺省補償處理程序調用緊貼的外層作用域的補償處理程序,調用的順序與這些作用域的完成順序相反。

          如果 compensate 活動中的作用域名被省略,那么這種 <compensate/> 形式將導致缺省行為被顯式地調用。當外層的故障處理程序或補償處理程序在為內層作用域執行缺省的補償的同時還需要進行另外的工作(例如更新容器或發送對外的通知)的時候,這種形式是有用的。請注意,附加到作用域 S 的故障處理程序或補償處理程序中的 <compensate/> 活動導致按缺省順序調用直接嵌套在 S 中的已完成的作用域的補償處理程序。除了顯式地調用 <compensate scope="Sx"/>(作用域 Sx 被直接嵌套在 S 中),這種活動的使用可與任何其它用戶指定的行為組合。正如期待的那樣,嵌套于 S 的作用域的顯式補償調用禁用了缺省順序的補償。

          11.3. 故障處理程序

          業務流程中的故障處理可被看作從作用域中的正常處理切換出來的模式。附加到作用域的可選的故障處理程序提供了定義一組定制的故障處理活動的方法,其語法定義為 catch 活動。被定義的每個 catch 活動能攔截某種故障(由全局唯一的故障 QName 和有與該故障關聯的數據的容器來定義)。如果沒有故障名,那么 catch 將攔截全部有適合類型的故障數據的故障。故障容器是可選的,這是因為故障可能沒有與之關聯的額外數據。對 invoke 活動的故障響應是故障的來源之一,根據 WSDL 操作中的故障定義,該故障有明顯的名稱和數據部分。通過編程,throw 活動也是故障的來源,它也有顯式給出的名稱和數據。BPEL4WS 定義了若干個有名稱和數據的標準故障,還可以有其它特定于平臺的故障,例如在業務流程的執行中發生的通信故障。catchAll 子句可被用來捕獲所有未被更特定的 catch 處理程序捕獲的故障。

            <faultHandlers>?
              <!-- there must be at least one fault handler or default -->
              <catch faultName="qname"? faultContainer="ncname"?>*
                activity
              </catch>
              <catchAll>?
                activity
              </catchAll>
            </faultHandlers>
          

          雖然補償的使用是故障處理程序的行為的重要部分,但是每個處理程序執行任意的活動,甚至可以是 <empty/>。在有故障處理程序的時候,故障處理程序將負責處理該故障。它可能再次拋出相同的故障或不同的故障,或者它可能這樣處理故障:進行清除并使正常的處理在外層作用域中繼續。

          發生故障的作用域可被認為是異常結束的作用域,無論該故障是否被捕獲并處理而沒有被故障處理程序再次拋出。從不為發生故障的作用域安裝補償處理程序。

          如果作用域 S 的故障處理程序處理了發生在 S 的故障而沒有再次拋出,那么在故障被處理后,以 S 作為源的鏈接的狀態值可被正常地求出,因為在外層作用域中的處理應被繼續。

          調用 Web 服務操作中已講過,invoke 活動有一個特別的快捷方式,即直接插入補償處理程序而不是顯式地使用緊貼的外層作用域。例如:

            <invoke partner="Seller" 
                    portType="SP:Purchasing" 
                    operation="SyncPurchase" 
                    inputContainer="sendPO" 
                    outputContainer="getResponse">
              <catch faultName="SP:POFault" faultContainer="POFault">
                <!-- handle the fault -->
              </catch>
            </invoke>
          

          在這個示例中,原先的 invoke 活動買件東西,一個故障處理程序被直接插入,以處理購買請求導致了故障響應這種情況。在標準的語法中(不用 invoke 的快捷方式)以等同地表示這個示例,如下所示:

          <scope>
            <faultHandlers>
              <catch faultName="SP:POFault" faultContainer="POFault">
                <!-- handle the fault -->
              </catch>
            </faultHandlers>
            <invoke partner="Seller" 
                    portType="SP:Purchasing" 
                    operation="SyncPurchase" 
                    inputContainer="sendPO" 
                    outputContainer="getResponse">
            </invoke>
          </scope>
          

          當作用域 C 的執行正常完成后,緊貼的外層作用域的故障處理程序和補償處理程序可以調用作用域 C 的補償處理程序。當作用域 C 的執行已開始但沒完成的時候,C 的故障處理程序可被調用。如果作用域在完成執行前發生故障,那么合適的故障處理程序取得控制,所有其它故障處理程序被卸載。在任何情況下,為同一個作用域運行多個故障處理程序是不可能的。

          請注意,可用性也適用于隱式故障處理程序和補償處理程序

          執行作用域 C 的故障處理程序的第一步是隱式地終止直接包括在 C 中的所有正在執行的活動的執行(請參閱活動終止的語義)。在故障處理程序的具體行為開始前就終止了正在執行的活動。這同樣適用于下面描述的隱式故障處理程序。

          11.3.1. 隱式故障處理程序和補償處理程序

          因為作用域名和補償處理程序的可見性限于下一個外層作用域,所以,如果外層作用域沒有補償處理程序或沒有某個故障的故障處理程序,那么將無法補償作用域。因為許多故障并不是程序引起的(或者說許多故障并不是操作調用的結果),所以期望在每個作用域中每個故障都有顯式處理程序是不合理的。因此,在沒有顯式處理程序的情況下,BPEL4WS 提供缺省的補償處理程序和故障處理程序。這些隱式處理程序的行為是按完成相應的作用域的相反的順序運行可用的補償處理程序。下面將用更準確的語言來定義這種行為。

          如果任何給定的作用域沒有(任何故障的)故障處理程序或補償處理程序,那么它們將被隱式地創建,它們的行為如下:

          故障處理程序

          • 按完成相應的作用域的相反的順序運行所有緊貼的外層作用域的補償處理程序。

          • 把故障拋向下一個外層作用域。

          補償處理程序

          • 按完成相應的作用域的相反的順序運行所有緊貼的外層作用域的補償處理程序。

          11.3.2. 活動終止的語義

          如前所述,執行作用域 C 的故障處理程序的第一步是隱式地終止直接包括在 C 中的所有正在執行的活動的執行。以下幾段定義了這句話對所有 BPEL4WS 活動類型的含義。

          invokereplyassign 等活動能較快結束,所以允許它們完成執行而不是在強制終止時中斷它們。已開始的表達式的求值也被允許完成。和 wait 一樣,receive 活動被過早地中斷并終止。終止概念不適用于 emptyterminatethrow

          所有的結構化的活動行為被中斷。while 的迭代被中斷且終止被應用到循環體活動。如果 switch 已選擇了一個分支,那么終止被應用到被選分支的活動。對于 pick 來說也是這樣。如果這些活動中的任一個尚未選擇分支,那么 switchpick 將停止執行并被終止。sequenceflow 構造是這樣被終止的:終止它們的執行并把終止應用到嵌套在其中的所有當前活動的活動。

          作用域在某種程度上提供了控制強制終止的語義的能力。當被終止的活動實際上是作用域時,該作用域的執行被中斷并運行標準故障 bpws:forcedTermination 的故障處理程序。請注意,這僅適用于在正常處理模式中的作用域。如果作用域已遇到內部故障且在執行故障處理程序,那么如上所述,所有其它故障處理程序(包括 bpws:forcedTermination 的處理程序)被卸載,強制的終止沒有影響。已開始執行的故障處理程序被允許完成它的執行。

          bpws:forcedTermination 故障的故障處理程序的編寫與其它故障處理程序的編寫相似,但這個故障處理程序不能再次拋出任何故障。即使在它的執行中發生未捕獲的故障,該故障也不被再次拋向下一個外層作用域。這是因為外層作用域已發生故障,這也是引起嵌套的作用域的被強制終止的原因。

          在其它方面,上述故障處理程序是正常的故障處理程序。執行該處理程序的第一步是隱式地(遞歸地)終止執行所有被直接包括在它的關聯作用域中的正在執行的活動。它可以執行補償活動。如果沒有該處理程序,那么將使用用于所有其它隱式故障處理程序的同一隱式行為來提供。

          請注意,嵌套的作用域的強制終止順序是從最里面開始,這是因為(如上所述)執行所有故障處理程序的第一步是隱式地(遞歸地)終止執行所有被直接包括在它的關聯作用域中的正在執行的活動。

          11.3.3. 故障處理程序和補償處理程序中的故障處理

          補償處理程序總是作為處理某個故障處理程序 E 的一部分被直接地或間接地調用。E 調用的補償處理程序的執行可能引起故障被拋出。如果該故障未被 E 調用的補償處理程序鏈中的作用域所捕獲,那么該故障將被看作 E 中的故障。

          如果在執行作用域 C 的故障處理程序 E 時有故障被拋出,那么可以使用 E 的作用域來捕獲該故障。如果 E 中的作用域沒有捕獲該故障,那么該故障被立即拋向 C 的父作用域且 E 的執行被過早地終止。實際上,E 有意再次拋出的故障與 E 的執行中意外發生的故障之間沒有區別。

          11.4. 可序列化的作用域

          當 containerAccessSerializable 屬性被設置為 "yes" 時,該作用域在管理對共享容器的訪問方面提供了并發控制。這樣的作用域被稱為可序列化的作用域(serializable scope)。可序列化的作用域絕不可以是嵌套的。被標記為 containerAccessSerializable="yes" 的作用域必須是葉作用域。

          假設兩個并發的可序列化的作用域 S1 和 S2 訪問一組公共的容器(在它們之外)以進行讀寫操作。可序列化的語義確保它們的執行結果是相同的,條件是在概念上對任何共享容器的有沖突的所有操作(讀/寫和寫/寫操作)被重新排序,以使 S1 中的所有操作的執行先于 S2 中的操作的執行,或者相反。實際用來確保可序列化的機制依賴于具體的實現。

          在可序列化的作用域中,錯誤處理功能的使用由以下規則來管理:

          • 可序列化的作用域的故障處理程序共享關聯的作用域的可序列化域,也就是說,在可序列化的作用域中發生故障的情況下,故障處理程序的執行被認為是可序列化行為的一部分(常用的實現說法是:在向故障處理程序過渡時不釋放鎖)。這是因為故障的修復需要共享的隔離環境,以提供可預測的行為。

          • 可序列化的作用域的補償處理程序并共享關聯的作用域的可序列化域。

          • 對于有補償處理程序的可序列化域,創建補償的狀態快照是可序列化行為的一部分。換句話說,總是可以對執行步驟重新排序,就好象作用域對共享的容器在完成前有足夠的獨有訪問權(包括創建快照)。

          可序列化的作用域的語義與數據庫事務中所用的標準隔離級別“可序列化”很相似,注意到這一點是有用的。

          12. 示例

          12.1. 運輸服務

          這個示例在描述基本的運輸服務的過程中演示了 BPEL4WS 抽象流程的使用。該服務處理定貨的運輸。從服務的角度看,定貨由多件貨物組成。該運輸服務提供兩種運輸:一種是貨物被保存然后一起被運輸,另一種是貨物被分成多次運輸直到所有的定貨被報帳。

          12.1.1. 服務描述

          運輸服務的上下文是客戶與服務間的雙方交互。這被模擬成下面的 serviceLinkType 定義:

          <slnk:serviceLinkType name="shippingLT"
             xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/">
             <slnk:role name="shippingService">
                <slnk:portType name="shippingServicePT"/>
             </slnk:role>
             <slnk:role name="shippingServiceCustomer">
                <slnk:portType name="shippingServiceCustomerPT"/>
             </slnk:role>
          </slnk:serviceLinkType>
          

          相應的消息和 portType 定義如下:

          <wsdl:definitions  
                        targetNameSpace="http://ship.org/wsdl/shipping"
                        xmlns:ship= ...>
          
          <message name="shippingRequestMsg">
             <part name="shipOrder" type="ship:shipOrder"/>
          </message>
          
          <message name="shippingNoticeMsg">
             <part name="shipNotice" type="ship:shipNotice"/>
          </message>
          
          <portType name="shippingServicePT">
             <operation name="shippingRequest">
                <input message="shippingRequestMsg"/>
             </operation>
          </portType>
          
          <portType name="shippingServiceCustomerPT">
             <operation name="shippingNotice">
                <input message="shippingNoticeMsg"/>
             </operation>
          </portType>
          
          </wsdl:definitions>
          

          12.1.2. 消息屬性

          與服務行為有關的屬性如下:

          • 運輸定單標識,用于使運輸通知與運輸定單相關(shipOrderID

          • 定單是否被運完(shipComplete

          • 定單中的貨物總數(itemsTotal

          • 在運輸通知中被引用的貨物數量,這樣,在分批運輸是可接受的情況下,我們可以使用貨物數量和 itemsTotal 來跟蹤運輸的整體完成情況(itemsCount

          以下是這些屬性及其別名的定義:

          <wsdl:definitions 
                 targetNamespace="http://example.com/shipProps/"
                 xmlns:sns="http://ship.org/wsdl/shipping"
                 xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/">
           
             <!-- types used in abstract processes are required to be finite domains. 
                  The itemCountType is restricted by range -->
          
             <wsdl:types>
                <xsd:schema> 
          ??????_<xsd:simpleType name="itemCountType"> 
          ??????_??????_<xsd:restriction base="xsd:int"> 
          ??????_??????_??????_<xsd:minInclusive value="1"/> 
          ??????_??????_??????_<xsd:maxInclusive value="50"/> 
          ??????_??????_</xsd:restriction> 
          ??????_</xsd:simpleType> 
                </xsd:schema>    
             </wsdl:types>
          
             <!-- a message type is defined here for internal use of the 
                  abstract process; it is not inlined because we need to
                  define a property relative to it -->
          
             <wsdl:message name="itemsShipped">
                <part name="value" type="ship:itemCountType"/>
             </wsdl:message>
             <bpws:property name="shipOrderID" type="xsd:int"/>
             <bpws:property name="shipComplete" type="xsd:boolean"/>
             <bpws:property name="itemsTotal" type="ship:itemCountType"/>
             <bpws:property name="itemsCount" type="ship:itemCountType"/>
             <bpws:property name="numItemsShipped" type="ship:itemCountType"/>
          
             <bpws:propertyAlias propertyName="tns:shipOrderID" 
                        messageType="sns:shippingRequestMsg"
                        part="shipOrder"
                        query="/ShipOrderRequestHeader/shipOrderID"/>
          
             <bpws:propertyAlias propertyName="tns:shipOrderID" 
                        messageType="sns:shippingNoticeMsg"
                        part="shipNotice"
                        query="/ShipNoticeHeader/shipOrderID"/>
          
             <bpws:propertyAlias propertyName="tns:shipComplete" 
                        messageType="sns:shippingRequestMsg"
                        part="shipOrder"
                        query="/ShipOrderRequestHeader/shipComplete"/>
          
             <bpws:propertyAlias propertyName="tns:itemsTotal" 
                         messageType="sns:shippingRequestMsg"
                         part="shipOrder"
                         query="/ShipOrderRequestHeader/itemsTotal"/>
          
             <bpws:propertyAlias propertyName="tns:itemsCount" 
                          messageType="sns:shippingNoticeMsg"
                          part="shipNotice"
                          query="/ShipNoticeHeader/itemsCount"/>
          
             <bpws:propertyAlias propertyName="tns:numItemsShipped" 
                           messageType="tns:itemsShipped"
                           part="value"
                           query="/"/>
          
          </wsdl:definitions>
          

          12.1.3. 流程

          下面是流程的定義。為了簡短起見,抽象流程定義省略了不少東西,例如完整的描述應說明(商業的或其它的)錯誤情況的處理。該流程的大致輪廓如下:

          receive shipOrder
          switch
             case shipComplete
                send shipNotice
             otherwise
                itemsShipped := 0
                while itemsShipped < itemsTotal
                itemsCount := opaque // non-deterministic assignment
                               // corresponding e.g. to 
                               // internal interaction with
                               // back-end system
                send shipNotice
                itemsShipped = itemsShipped + itemsCount
          

          以下是更完整的版本:

          <process name="shippingService"
                targetNameSpace="http://acme.com/shipping"
                   xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
                xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                xmlns:sns="http://ship.org/wsdl/shipping"
                   xmlns:props="http://example.com/shipProps/"
                   abstractProcess="yes">
          
          <partners>
            <partner name="customer"
                     serviceLinkType="sns:shippingLT"
                  partnerRole="shippingServiceCustomer"
                  myRole="shippingService"/>
          </partners>
          
          <containers>
            <container name="shipRequest"
                       messageType="sns:shippingRequestMsg"/>
            <container name="shipNotice"
                  messageType="sns:shippingNoticeMsg"/>
            <container name="itemsShipped"
                       messageType="props:itemsShipped"/>
          </containers>
          
          <correlationSets>
            <correlationSet name="shipOrder"
                   properties="props:shipOrderID"/>
          </correlationSets>
          
          <sequence>
          
            <receive partner="customer"
                     portType="sns:shippingServicePT"
                  operation="shippingRequest"
                  container="shipRequest">
              <correlations>
                <correlation set="shipOrder" initiation="yes"/>
              </correlations>
            </receive>
          
            <switch>
              <case condition=
                 "bpws:getContainerProperty('shipRequest','props:shipComplete')" >
                <sequence>
               <assign>
                    <copy>
                      <from container="shipRequest" property="props:itemsCount"/>
                      <to container="shipNotice" property="props:itemsCount"/>
                    </copy>
                  </assign>
                  <invoke partner="customer"
                  portType="sns:shippingServiceCustomerPT"
                        operation="shippingNotice"
                  inputContainer="shipNotice">
                 <correlations>
                   <correlation set="shipOrder" pattern="out"/>
                 </correlations>
               </invoke>
                </sequence>
              </case>
              <otherwise>
                <sequence>
                  <assign>
                    <copy>
                   <from expression="0"/>
                   <to container="itemsShipped" part="value"/>
                    </copy>
               </assign>
               <while condition=
                   "bpws:getContainerProperty('itemsShipped','props:numItemsShipped') <
                    bpws:getContainerProperty('shipRequest','props:itemsTotal')">
                     <sequence>
                     <assign>
                          <copy>
                         <from opaque="yes"/>
                         <to container="shipNotice" property="props:itemsCount"/>
                          </copy>
                    </assign>
                       <invoke partner="customer"
                         portType="sns:shippingServiceCustomerPT"
                               operation="shippingNotice"
                         inputContainer="shipNotice">
                       <correlations>
                          <correlation set="shipOrder" pattern="out"/>
                       </correlations>
                    </invoke>
                    <assign>
                          <copy>
                         <from expression=
                                  "bpws:getContainerProperty('itemsShipped',
                                   'props:numItemsShipped')+ 
                                   bpws:getContainerProperty('shipNotice',
                                   'props:itemsCount')"/>
                         <to container="itemsShipped" part="value"/>
                          </copy>  
                    </assign>
                     </sequence>
                </while>
                 </sequence>
              </otherwise>
            </switch>
          </sequence>
          
          </process>
          

          12.2. 貸款審批

          這個示例考慮的是一個簡單的貸款審批 Web 服務,客戶可以通過該服務提供的端口發送他們的貸款申請。該服務的客戶發送的貸款申請中包括個人信息和申請的數額。根據這些信息,貸款服務運行一個簡單的流程,運行的結果是“貸款被批準”消息或“貸款被拒絕”消息。作出審批決定的方式有兩種,這取決于申請的數額以及與申請人有關的風險。對于小額貸款(小于 $10,000)和低風險個人,審批是自動的。對于大額貸款或中額貸款和高風險個人,每個信用申請需被更仔細地研究。所以,為了處理每個申請,貸款服務使用兩個其它服務提供的功能。在小額貸款可用的簡化的處理中,“風險評估”服務被用來獲取與提出申請的個人有關的風險的快速評估。當簡化的審批流程不適用的時候,完整的“貸款審批”服務(可能需要貸款專家的直接參與)被用來獲取申請的全面評估。

          12.2.1. 服務描述

          下面顯示的是該服務支持的 WSDL portType(“loanServicePT”portType)。這里假定一個獨立的“loan.org”聯盟已提供了貸款服務 portType 的定義以及風險評估和全面貸款審批服務的定義,所以所有所需的 WSDL 定義出現在相同的 WSDL 文檔中。具體地說,這里定義了提供風險評估和審批功能的 Web 服務的 portType,還定義了與使用這些 portType 有關的所有所需的服務鏈接類型。

          <definitions 
                targetNamespace="http://loans.org/wsdl/loan-approval"
                xmlns="http://schemas.xmlsoap.org/wsdl/"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"    
                 xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/"      
                xmlns:lns="http://loans.org/wsdl/loan-approval">
          
          
          <message name="creditInformationMessage">
             <part name="firstName" type="xsd:string"/>
             <part name="name" type="xsd:string"/>
             <part name="amount" type="xsd:integer"/>
          </message>
          
          <message name="approvalMessage">
             <part name="accept" type="xsd:string"/>
          </message>
          
          <message name="riskAssessmentMessage">
             <part name="level" type="xsd:string"/>
          </message>   
          
          <message name="errorMessage">
             <part name="errorCode" type="xsd:integer"/>
          </message>
          
          <portType name="loanServicePT">
             <operation name="request">
                <input message="lns:creditInformationMessage"/>
                <output message="lns:approvalMessage"/>
                <fault name="unableToHandleRequest" 
                       message="lns:errorMessage"/>
             </operation>
          </portType>
          
          <portType name="riskAssessmentPT">
             <operation name="check">
                <input message="lns:creditInformationMessage"/>
                <output message="lns:riskAssessmentMessage"/>
                <fault name="loanProcessFault" 
                       message="lns:errorMessage"/>
             </operation>
          </portType>
          
          <portType name="loanApprovalPT">
             <operation name="approve">
                <input message="lns:creditInformationMessage"/>
                <output message="lns:approvalMessage"/>
                <fault name="loanProcessFault" 
                       message="lns:errorMessage"/>
             </operation>
          </portType>      
          
          <slnk:serviceLinkType name="loanServiceLinkType">
             <slnk:role name="customer">
                 <slnk:portType name="lns:loanServicePT"/>
             </slnk:role>
          </slnk:serviceLinkType>
          
          <slnk:serviceLinkType name="loanApprovalLinkType">
             <slnk:role name="approver">
                 <slnk:portType name="lns:loanApprovalPT"/>
             </slnk:role>   
          </slnk:serviceLinkType>
          
          <slnk:serviceLinkType name="riskAssessmentLinkType">
             <slnk:role name="assessor">
                 <slnk:portType name="lns:riskAssessmentPT"/>
             </slnk:role>   
          </slnk:serviceLinkType>
          
          </definitions>
          

          12.2.2. 流程

          在下面定義的業務流程中,初始的 <receive> 活動和匹配的 <reply> 活動表示與客戶的交互。<invoke> 元素表示風險評估和貸款審批服務的使用。所有這些活動被包括在 <flow> 中,根據相應的 <link> 元素所表示的依賴關系來(可能是并行地)執行這些活動。請注意,附加在鏈接的 <source> 元素上的過渡條件決定激活哪個鏈接。由于 <process> 元素的“suppressJoinFailure”屬性值為 "yes",所以死路刪除已被啟用。這暗示,由于某些鏈接被設置為 false,該決定的后果可被傳播而某些活動的執行可被跳過。

          因為被調用的操作可能返回類型是“loanProcessFault”的故障,所以需要提供故障處理程序。當故障發生時,控制被轉移給故障處理程序,故障處理程序中的 <reply> 元素被用來把類型是“unableToHandleRequest”的故障響應返回給貸款申請人。

          <process name="loanApprovalProcess" 
                   targetNamespace="http://acme.com/loanprocessing" 
                   xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
                   xmlns:lns="http://loans.org/wsdl/loan-approval"
                   suppressJoinFailure="yes">
          
             <partners>
                <partner name="customer" 
                         serviceLinkType="lns:loanServiceLinkType"
                         partnerRole="customer"/>
                <partner name="approver" 
                         serviceLinkType="lns:loanApprovalLinkType"
                         partnerRole="approver"/>
                <partner name="assessor" 
                         serviceLinkType="lns:riskAssessmentLinkType"
                         partnerRole="assessor"/>
             </partners>
          
             <containers>
               <container name="request" 
                          messageType="lns:creditInformationMessage"/>
               <container name="risk" 
                          messageType="lns:riskAssessmentMessage"/>
               <container name="approval" 
                          messageType="lns:approvalMessage"/>
               <container name="error" 
                          messageType="lns:errorMessage"/>
             </containers>
          
             <faultHandlers>
                <catch faultName="lns:loanProcessFault" 
                       faultContainer="error">
                   <reply   partner="customer"
                            portType="lns:loanServicePT" 
                            operation="request"
                            container="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 partner="customer" 
                         portType="lns:loanServicePT" 
                         operation="request" 
                         container="request" createInstance="yes">
                   <source linkName="receive-to-assess"
                      transitionCondition=
                        "bpws:getContainerData('request','amount')< 10000"/>          
                   <source linkName="receive-to-approval"
                      transitionCondition=
                        "bpws:getContainerData('request','amount')>=10000"/>
                </receive>
          
                <invoke  partner="assessor" 
                         portType="lns:riskAssessmentPT" 
                         operation="check"
                         inputContainer="request"  
                         outputContainer="risk">
                   <target linkName="receive-to-assess"/>
                   <source linkName="assess-to-setMessage" 
                      transitionCondition=
                        "bpws:getContainerData('risk','level')='low'"/>
                   <source linkName="assess-to-approval" 
                      transitionCondition=
                        "bpws:getContainerData('risk','level')!='low'"/>
                </invoke>
          
                <assign>
                   <target linkName="assess-to-setMessage"/>
                   <source linkName="setMessage-to-reply"/>
                   <copy>
                      <from expression="'yes'"/>
                      <to container="approval" part="accept"/>
                   </copy>
                </assign>
          
                <invoke  partner="approver" 
                         portType="lns:loanApprovalPT" 
                         operation="approve" 
                         inputContainer="request" 
                         outputContainer="approval">
                   <target linkName="receive-to-approval"/>
                   <target linkName="assess-to-approval"/>
                   <source linkName="approval-to-reply" />
                </invoke>
          
                <reply   partner="customer" 
                         portType="lns:loanServicePT" 
                         operation="request" 
                         container="approval">
                   <target linkName="setMessage-to-reply"/>
                   <target linkName="approval-to-reply"/>
                </reply>
             </flow>
          
          </process>
          

          12.3. 多個啟動活動

          一個流程可以有多個創建流程實例的活動。這種情況的示例是拍賣行運行的(簡化的)業務流程。該業務流程的目的如下:收集來自某次拍賣的買賣雙方的信息;向某個拍賣注冊服務報告適當的拍賣結果;然后把注冊結果返回給買賣雙方。所以,該業務流程有兩個啟動活動,一個用于接收賣方信息,另一個用于接收買方信息。因為拍賣標識能唯一地識別某次拍賣,所以買賣雙方需在發送他們的數據時提供拍賣標識。賣方請求和買方請求到達拍賣行的順序是隨機的。所以,當這樣的請求到達時,需檢查業務流程實例是否已經存在。如果還不存在,那么就創建業務流程實例。當接收到這兩個請求后,拍賣注冊服務被調用。因為調用是異步的,拍賣行把拍賣標識傳遞給拍賣注冊服務。拍賣注冊服務在它的回答中返回這個拍賣標識以使拍賣行找到正確的業務流程實例。因為有許多買方和賣方,買賣雙方都需要提供他們的服務引用以使拍賣服務可以正確地響應。另外,拍賣行需向拍賣注冊服務提供它自己的服務引用以使拍賣注冊服務可以把響應返回給拍賣行。

          12.3.1. 服務描述

          拍賣服務提供兩個名為 sellerPT 和 buyerPT 的端口類型,這兩個端口類型有可用于接受由賣方和買方提供的數據的適當的操作。因為業務流程的處理時間是漫長的,所以拍賣服務通過合適的端口類型(sellerAnswerPT 和 buyerAnswerPT)來響應賣方和買方。這些 portType 被正確地組合成兩個服務鏈接類型,一個是用于賣方的 sellerAuctionHouseLT,另一個是用于買方的 buyerAuctionHouseLT。

          拍賣服務需要兩個為調用拍賣注冊服務提供的端口類型(auctionRegistrationPT 和 auctionRegistrationAnswerPT)。這些端口類型是合適的服務鏈接類型 auctionHouseAuctionRegistrationServiceLT 的一部分。

          <definitions 
              targetNamespace="http://www.auction.com/wsdl/auctionService" 
              xmlns:tns="http://www.auction.com/wsdl/auctionService" 
              xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/"
              xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
              xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
              xmlns:xsd="http://www.w3.org/2001/XMLSchema"
              xmlns="http://schemas.xmlsoap.org/wsdl/">
           
          <!-- Messages for communication with the seller -->
           
            <message name="sellerData">
               <part name="creditCardNumber" type="xsd:string"/>
               <part name="shippingCosts" type="xsd:integer"/>
               <part name="auctionId" type="xsd:integer"/>
               <part name="serviceReference" type="sref:serviceReferenceType"/>
            </message>
            <message name="sellerAnswerData">
               <part name="thankYouText" type="xsd:string"/>
            </message>
           
          <!-- Messages for communication with the buyer -->
           
            <message name="buyerData">
               <part name="creditCardNumber" type="xsd:string"/>
               <part name="phoneNumber" type="xsd:string"/>
               <part name="ID" type="xsd:integer"/>
               <part name="serviceReference" type="sref:serviceReferenceType"/>
            </message>
            <message name="buyerAnswerData">
               <part name="thankYouText" type="xsd:string"/>
            </message>
           
          <!-- Messages for communication with the auction registration service -->
           
            <message name="auctionDetails">
               <part name="auctionId" type="xsd:integer"/>
               <part name="amount" type="xsd:integer"/>
            </message>
            <message name="auctionDetailsAnswer">
               <part name="registrationId" type="xsd:integer"/>
               <part name="auctionId" type="xsd:integer"/>
               <part name="auctionHouseServiceReference" 
                           type="sref:serviceReferenceType"/>
            </message>
            
          <!-- Port types for interacting with the seller -->
           
            <portType name="sellerPT">
               <operation name="submit">
                  <input message="tns:sellerData"/>
               </operation>
            </portType>
            <portType name="sellerAnswerPT">
               <operation name="answer">
                  <input message="tns:sellerAnswerData"/>
               </operation>
            </portType>
           
          <!-- Port types for interacting with the buyer -->
           
            <portType name="buyerPT">
               <operation name="submit">
                  <input message="tns:buyerData"/>
               </operation>
            </portType>
            <portType name="buyerAnswerPT">
               <operation name="answer">
                  <input message="tns:buyerAnswerData"/>
               </operation>
            </portType>
           
          <!-- Port types for interacting with the auction registration service -->
           
            <portType name="auctionRegistrationPT">
               <operation name="process">
                  <input message="tns:auctionDetails"/>
               </operation>
            </portType>
            <portType name="auctionRegistrationAnswerPT">
               <operation name="answer">
                  <input message="tns:auctionRegAnswer"/>
               </operation>
            </portType>
          
          <!-- Context type used for locating business process via auction Id -->
           
            <bpws:property name="auctionId"
                           type="xsd:string"/>
          
            <bpws:propertyAlias propertyName="tns:auctionId"
                               messageType="tns:sellerData" 
                               part="auctionId"/>
          
            <bpws:propertyAlias propertyName="tns:auctionId"
                                     messageType="tns:buyerData"
                                     part="ID"/>
            <bpws:propertyAlias propertyName="tns:auctionId"
                                    messageType="tns:auctionDetailsAnswer"
                                    part="auctionId"/>
             <bpws:propertyAlias propertyName="tns:auctionId"
                                    messageType="tns:auctionDetails"
                                    part="auctionId"/>
           
           
          <!-- Service link type for seller/auctionHouse -->
           
            <slnk:serviceLinkType name="tns:sellerAuctionHouseLT">     
               <slnk:role name="auctionHouse">
                  <slnk:portType name="tns:sellerPT"/>
               </slnk:role>
               <slnk:role name="seller">
                  <slnk:portType name="tns:sellerAnswerPT"/>
               </slnk:role>
            </slnk:serviceLinkType>
           
          <!-- Service link type for buyer/auctionHouse -->
           
            <slnk:serviceLinkType name="buyerAuctionHouseLT">      
               <slnk:role name="auctionHouse">
                  <slnk:portType name="tns:buyerPT"/>
               </slnk:role>
               <slnk:role name="buyer">
                  <slnk:portType name="tns:buyerAnswerPT"/>
               </slnk:role>
            </slnk:serviceLinkType>
           
          <!-- Service link type for auction house/auction 
               registration service -->
           
            <slnk:serviceLinkType name="auctionHouseAuctionRegistrationServiceLT">
               <slnk:role name="auctionRegistrationService">
                 <slnk:portType name="tns:auctionRegistrationPT"/>
               </slnk:role>
               <slnk:role name="auctionHouse">
                 <slnk:portType name="tns:auctionRegistrationAnswerPT"/>
               </slnk:role>
            </slnk:serviceLinkType>
          </definitions>
          

          12.3.2. 流程

          由拍賣行提供的業務流程的 BPEL4WS 定義如下:

          <process name="auctionService"
                 targetNamespace="http://www.auction.com"
                 containerAccessSerializable="no"
                 xmlns:as="http://www.auction.com/wsdl/auctionService" 
                 xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
                 xmlns="http://schemas.xmlsoap.org/ws/2002/07/business-process/">
                   
           
          <!-- Partners -->
           
            <partners>
               <partner name="seller" 
                        serviceLinkType="as:sellerAuctionHouseLT"
                        myRole="auctionHouse" partnerRole="seller"/>
               <partner name="buyer" 
                        serviceLinkType="as:buyerAuctionHouseLT"
                        myRole="auctionHouse" partnerRole="buyer"/>
               <partner name="auctionRegistrationService"
                        serviceLinkType=
                        "as:auctionHouseAuctionRegistrationServiceLT"
                        myRole="auctionHouse" 
                        partnerRole="auctionRegistrationService"/>
            </partners>
           
          <!-- Containers -->
           
            <containers>
               <container name="sellerData" messageType="as:sellerData"/>
               <container name="sellerAnswerData" messageType="as:sellerAnswerData"/>
               <container name="buyerData" messageType="as:buyerData"/>
               <container name="buyerAnswerData" messageType="as:buyerAnswerData"/>
               <container name="auctionRegistrationData"
                          messageType="as:auctionDetails"/>
               <container name="auctionRegistrationResponse"
                          messageType="as:auctionRegAnswer"/>
            </containers>
           
          <!-- Correlation set for correlating buyer and seller request 
               as well as auction house and auction registration service
               exchange -->
           
            <correlationSets>
               <correlationSet name="auctionIdentification"
                  properties="as:auctionId"/>
                  
            </correlationSets>
           
          <!-- Structure of the business process -->
           
            <sequence>
           
          <!-- Process buyer and seller request in parallel
               Either one can create a process instance -->
           
               <flow>
           
          <!-- Process seller request --> 
              
                  <receive name="acceptSellerInformation"
                           partner="seller"
                           portType="as:sellerPT"
                           operation="provide"
                           container="sellerData"
                           createInstance="yes">
                      <correlations>
                           <correlation set="auctionIdentification"
                                        initiation="yes"/>
                           </correlations>              
                           
                   </receive>
           
          <!-- Process buyer request --> 
           
                  <receive name="acceptBuyerInformation"
                           partner="buyer"
                           portType="as:buyerPT"
                           operation="provide"
                           container="buyerData"
                           createInstance="yes">
                      <correlations>
                           <correlation set="auctionIdentification"
                                        initiation="yes"/>
                      </correlations>
                  </receive> 
                           
           
                </flow>
           
          <!-- Invoke auction registration service 
               by setting the target service reference
               and setting my own service reference for call back
               and receiving the answer 
               Correlation of request and answer is via auction Id -->
           
                <assign>
                   <copy>
                      <from>
                         <sref:serviceReference>
                            <sref:service name="ars:RegistrationService"
                               xmlns:ars="http://auctionRegistration.com"/>
                         </sref:serviceReference>
                      </from>
                      <to partner="auctionRegistrationService"/>
                   </copy>
                </assign>
           
                <assign>
                   <copy>
                     
                      <from partner="auctionRegistrationService"
                            serviceReference="myRole"/>
                      <to container="auctionRegistrationData"
                          part="auctionHouseServiceRef"/>
                   </copy>
                </assign>
           
                <invoke name="registerAuctionResults"
                        partner="auctionRegistrationService"
                        portType="as:auctionRegistrationPT"
                        operation="process"
                        inputContainer="auctionRegistrationData">
                   <correlations>
                        <correlation set="auctionIdentification"/>                                
                   </correlations>  
                </invoke> 
                        
                <receive name="receiveAuctionRegistrationInformation"
                         partner="auctionRegistrationService"
                         portType="as:auctionRegistrationAnswerPT"
                         operation="answer"
                         container="auctionRegistrationAnswerData">
                         
                   <correlations>
                        <correlation set="auctionIdentification"/>
                   </correlations>
              </receive>
          
          <!-- Send responses back to seller and buyer -->
           
                <flow>
           
          <!-- Process seller response by
               setting the seller to the service reference provided by the seller
               and invoking the response -->
           
                   <sequence>
           
                       <assign>
                          <copy>
                             <from container="sellerData"
                                   part="serviceReference"/>
                             <to partner="seller"/>
                          </copy>
                       </assign>
            
                       <invoke name="respondToSeller"
                               partner="seller"
                               portType="as:sellerAnswerPT"
                               operation="answer"
                               inputContainer="sellerAnswerData"/>
           
                   </sequence>
           
          <!-- Process buyer response by
               setting the buyer to the service reference provided by the buyer
               and invoking the response -->
           
                   <sequence>
           
                       <assign>
                          <copy>
                             <from container="buyerData" 
                                   part="serviceReference"/>
                             <to partner="buyer"/>
                          </copy>
                       </assign>
            
                       <invoke name="respondToBuyer"
                               partner="buyer"
                               portType="as:buyerAnswerPT"
                               operation="answer"
                               inputContainer="buyerAnswerData"/>
           
                   </sequence>
           
                </flow>
           
             </sequence>
           
          </process>
          

          13. 未來的發展方向

          BPEL4WS 是正在被改進的語言。本規范中缺少許多必需的功能。未來的版本中將包括這些功能。以下幾節將討論一些顯而易見的擴展,這些擴展將被添加到 BPEL4WS 中。

          13.1. 作用域

          作用域所提供的功能是把多個活動分為一組并把屬性賦給這個作用域,例如故障處理程序和補償處理程序。以下特征需被添加到作用域。

          13.1.1. 容器

          目前,只能在流程級別聲明容器,使整個流程成為可以訪問容器的作用域。換句話說,所有的容器都是全局的。未來的版本將允許在所有的作用域中聲明容器,從而允許定義僅在本地作用域中可見的且可訪問的容器。這可以簡化不少東西,比如說補償處理程序的編寫。

          除了用于同步信號外,本地容器還使通過鏈接來發送數據變得有吸引力。本地容器與基于鏈接的數據傳輸的組合將大大減少對使用可序列化的作用域的顯式并發控制的需求。

          對并發訪問共享的容器所產生的問題進一步的分析將有可能簡化功能并更好地避免死鎖和干擾。在這些方面,BPEL4WS 將在未來的版本中得到改進。

          13.1.2. 事件處理程序

          業務流程常常需要準備應對在流程執行的指定部分中的任何時候可能出現的未作安排的業務事件。作用域被用來描述流程執行部分,事件處理程序概念將被添加到作用域中,以模擬異步事件的處理。整個流程可以有一組在流程執行中總是可用的事件處理程序。有兩種事件將被支持。第一種是對應于 WSDL 中進站的請求/響應或單向操作的事件。例如,狀態查詢很可能是請求/響應操作而取消可能是單向操作。第二種事件可以是在用戶設定的時刻發出的定時器警報。與故障處理程序和補償處理程序不同,事件處理程序將被考慮為該作用域的正常行為的一部分。

          13.1.3. 重疊作用域

          目前,作用域是互相嵌套的。因為作用域與許多不同的屬性關聯,所以有不同屬性的作用域很可能有一些共同的活動。這可能要求作用域可以重疊。這是需要進一步研究的領域。

          13.1.4. 原子作用域

          業務流程常常是“事務的”,其含義是它們所執行的活動要求可預測的一致的結果。雖然在某種意義上持續性屬于私有的實現范圍,但是經常要求以這樣的方式執行一組活動:要么全部成功完成,要么不執行這些活動(或消除它們的影響)。例如,接收請求、執行某些數據處理和回答請求這三個活動常常可以這種方式被耦合在一起。這常常被稱為原子性,在未來的版本中將添加定義有原子性屬性的作用域的功能。

          13.1.5. 補償

          補償是撤銷整個業務流程的影響的方法,也是撤銷部分業務流程的影響的方法。目前的規范提供了基本的支持。還需進一步改進補償行為。例如,目前的補償是完全獨立的。它并不受它運行所在的流程實例的當前活動狀態的影響,它也不能影響該狀態。一般來說,這顯然不符合實際。輸入和輸出參數將被添加到補償處理程序,以支持在受控的方式中活動狀態與補償的相互影響。其它可能的改進包括在失敗的情況下再次補償和新的缺省補償模式(目前支持的是“相反的順序”模式)。

          13.2. 生命周期和查詢

          13.2.1. 暫掛/恢復

          有時候,有必要使業務流程的執行暫掛(停機)一段時間或顯式地被合適的操作恢復。這類暫掛/恢復活動主要被用于事件處理程序,以暫掛和恢復整個業務流程或僅僅是某個作用域的處理。另外,目前的 terminate 活動終止整個流程。在有些情況下,僅僅終止某個作用域中的處理就足夠了。

          13.2.2. 查詢

          目前的草案不支持查詢業務流程的狀態的功能,這在執行業務流程時是需要的。選項的指定(例如所提供的信息的詳細信息)必須被支持。

          13.3. 服務組成

          因為一般來說,BPEL4WS 流程提供和消費多個 Web 服務接口,所以這樣的流程可被看作由其它 Web 服務組成的一組 Web 服務。服務鏈接所提供的關系概念在建立組成形式方面也很重要。這顯然是需要進一步開發的領域,未來版本的 BPEL4WS 將參與這方面的開發。

          13.4. 與 WS-Transaction 規范的關系

          BPEL4WS 在作用域的語法構造的基礎上定義了長期運行的業務事務(long-running business transactions,LRT)概念。對于存在分布式的業務流程或跨越多個供應商的實現的環境,WS-Transaction 規范 [12] 將提供機制來:

          • 為分布式作用域定義在業務事務中可被理解的全局協定上下文。

          • 允許分布式流程中的參與者注冊故障處理和補償通知(根據列出的 LRT 行為)。

          請參閱附錄 C,了解基于 WS-Transaction 概念的 BPEL4WS LRT 的詳細模型。

          另外,多個業務流程實例常常需要一起運行,以使共享的工作單元被一致地完成。這些流程中個別 LRT 的協調也需要使用 WS-Transaction 規范中列出的協調協議(根據在 WS-Transaction 中列出的協定行為)。

          14. 安全性注意事項

          因為消息可以被篡改或偽造,所以強烈推薦業務流程實現使用 WS-Security 來確保消息在傳輸過程中或駐留在目的地時未被篡改或偽造。類似地,無效或過期的消息可被再次使用,或者未專門與特定的消息相關聯的消息頭可被引用。因此,在使用 WS-Security 時,簽名必須包含語義重要的消息頭和消息體(以及任何其它有關數據),這樣它們就不會被獨立地分開并再次被使用了。

          在業務流程間用于通信的消息傳遞協議易遭受各種形式的重播攻擊。除上面列出的機制外,消息還應該在簽名中包含一個消息時間戳(如 WS-Security 中所述)。接收者可以使用時間戳信息為業務流程高速緩存最近的消息、檢測重復的傳輸并阻止潛在的重播攻擊。

          還應該注意,業務流程的實現易遭受各種形式的拒絕服務攻擊。遵守本規范的業務流程執行系統的實現者應該把這一點考慮進去。

          15. 致謝

          Achille Fokoue、Ashok Malhotra 和 Bob Schloss 為開發和驗證 XML Schema 提供了幫助。

          Tony Andrews 和 Marc Levy 為定義抽象流程提供了幫助。

          Tony Hoare 和 Marc Shapiro 經深思熟慮后提出了他們對 BPEL4WS 語言的概念的看法。

          Jonathan Marsh 建議推廣對外部(查詢和表達式)語言的依賴關系。

          Tom Freund 和 Tony Storey 引導我們準確地定義與 WS-Transaction 中的協調框架的關系。

          Martin Nally 為改善 BPEL4WS 語言的可用性提供了幫助。

          16. 參考資料

          [1] W3C 推薦“XML 規范
          [2] W3C 紀要“Simple Object Access Protocol (SOAP) 1.1
          [3] W3C 紀要“Web Services Description Language (WSDL) 1.1
          [4] 業界倡議“Universal Description, Discovery and Integration
          [5] XLANG:Web Services for Business Process Design
          [6] WSFL:Web Services Flow Language 1.0
          [7] W3C 提議的推薦“XML Schema Part 1: Structures
          [8] W3C 提議的推薦“XML Schema Part 2: Datatypes
          [9] W3C 推薦“XML Path Language (XPath) Version 1.0
          [10]“Sagas”,H. Garcia-Molina 和 K. Salem,Proc. ACM SIGMOD(1987 年)。
          [11]“Trends in systems aspects of database management”,I.L. Traiger,Proc. 2nd Intl. Conf. on Databases (ICOD-2),Wiley & Sons 1983 年。
          [12]“Web Services Transaction”,BEA、IBM 和 Microsoft,2002 年。
          [13]“Key words for use in RFCs to Indicate Requirement Levels”,RFC 2119,S. Bradner,Harvard University,1997 年 3 月。
          [14]“Uniform Resource Identifiers (URI): Generic Syntax”,RFC 2396,T. Berners-Lee,R. Fielding,L. Masinter,MIT/LCS,U.C. Irvine,Xerox Corporation,1998 年 8 月。

          附錄 A 標準故障

          下面的列表指定了 BPEL4WS 規范中定義的標準故障。所有這些故障被命名在對應于 URI“http://schemas.xmlsoap.org/ws/2002/07/business-process/”的 BPEL4WS 名稱空間的標準前綴 bpws: 中。

          故障名原因
          selectionFailure拋出的條件是在函數(例如 bpws:getContainerData)中或在賦值中執行的選擇操作遇到錯誤。
          conflictingReceive拋出的條件是具有相同的 partner、portType 和 operation 的多個 receive 活動或等同的代碼(目前是 pick 活動中的 onMessage 分支)被同時啟用。
          conflictingRequest拋出的條件是多個來自某個端口類型和操作的相同的伙伴的同步進站請求是活動的。
          mismatchedAssignmentFailure拋出的條件是在 assign 活動中遇到不兼容的類型。
          joinFailure拋出的條件是活動的連結條件的值是 false。
          forcedTermination 拋出的條件是外層作用域中發生故障。
          correlationViolation拋出的條件是 invoke、receive 或 reply 等活動中處理的消息內容與指定的相關性信息不匹配。
          uninitializedContainer拋出的條件是企圖訪問消息容器中未初始化部分的值。
          repeatedCompensation拋出的條件是安裝的補償處理程序被調用多次。

          附錄 B 屬性和缺省值

          下面的列表指定了流程級別和活動級別的所有標準屬性的缺省值。這張列表并不包括特定于活動的屬性(例如 invoke 活動中的 partner)。

          參數缺省值
          queryLanguagehttp://www.w3.org/TR/1999/REC-xpath-19991116
          expressionLanguagehttp://www.w3.org/TR/1999/REC-xpath-19991116
          suppressJoinFailureno
          containerAccessSerializableno
          abstractProcessno
          initiationno
          pattern沒有缺省值
          createInstanceno
          enableInstanceCompensationno
          joinCondition進站鏈接狀態的析取

          附錄 C 協調協議

          使用 WS-Transaction [12] 的協議框架來表達作用域間的故障和補償處理關系是重要的。具體地說,這一節講述怎樣使用 WS-Transaction 規范中定義的 BusinessAgreement 協議來模擬外層作用域與它的每個嵌套的作用域間的關系。BusinessAgreement 協議被用來啟用業務活動的分布式的協調。BPEL4WS 在使用該協議時假定在 BPEL4WS 中實際并不需要單個服務中的本地化行為,因此也不需要該協議的幾個功能(包括確認信號 ForgetError 消息和 Replay 消息)。

          BPEL4WS 作用域的協調協議

          1. 嵌套的作用域的執行可能成功地完成。在這種情況下,嵌套的作用域被安裝了補償處理程序。可用從嵌套的作用域到它的父作用域的 Completed 信號來模擬這種情況。

          2. 嵌套的作用域的執行可能遇到內部故障。在這種情況下,該作用域總是不成功地終止。
            1. 如果故障處理程序向它的外層作用域再次拋出故障,那么可用從嵌套的作用域到它的父作用域的 Faulted 信號來模擬這種情況。

            2. 如果故障被處理且未被再次拋出,那么該作用域從容地從它的父作用域的工作中退出。可用從嵌套的作用域到它的父作用域的 Exited 信號來模擬這種情況。
          3. 當嵌套的作用域完成后,父作用域(的故障處理程序或補償處理程序)可以要求它通過調用它的補償處理程序來補償它自己。可用從父作用域到嵌套的作用域的 Compensate 信號來模擬補償操作。

          4. 在成功完成補償后,嵌套的作用域向它的父作用域發送 Compensated 信號。

          5. 補償處理程序自身可能產生內部故障。在這種情況下
            1. 如果該故障未被補償處理程序的作用域處理,那么該故障被再次拋到父作用域。可用從嵌套的作用域到它的父作用域的 Faulted 信號來模擬這種情況。

            2. 如果該故障被處理且未被再次拋出,那么我們假定該補償能夠成功完成。在這種情況下,嵌套的作用域向它的父作用域發送 Compensated 信號。
          6. 如果在父作用域中有一個與嵌套的作用域的工作無關的故障,那么父作用域將要求嵌套的作用域通過發送 Cancel 信號來提前放棄它的工作。

          7. 在接收到 cancel 信號后,嵌套的作用域將中斷并終止它的執行(就好象出現了內部故障),然后把 Canceled 信號返回給父作用域。

          8. 最后,當父作用域決定不再需要已完成的嵌套的作用域的補償時,該父作用域向嵌套的作用域發送 Close 信號。在丟棄補償處理程序后,嵌套的作用域發出 Closed 信號作為響應。

          9. 當來自嵌套的作用域的 Completed 信號與來自父作用域的 Cancel 信號出現競爭時,Completed 信號勝出,也就是說,可以認為嵌套的作用域已完成而 Cancel 信號被忽略。

          10. 如果 Cancel 信號被發送到已產生內部故障的嵌套的作用域,那么 Cancel 信號被忽略,該作用域將最終向父作用域發送 Faulted 信號或 Exited 信號。

          以上的 BusinessAgreement 協議狀態圖總結了前面的討論。在這張圖中,父(外層)作用域產生 CancelCompensateForgetClose 等信號,嵌套的作用域產生 CompletedFaultedExited、Compensated、CanceledClosed 等信號。需要強調的是,這些狀態表示父作用域與某一個嵌套的作用域間的關系的狀態。但是,除了發生信號競爭的情況,可以說這些狀態幾乎能表示嵌套的作用域自身的狀態。請注意,這張圖并沒有反映在上面的 I 點和 J 點討論的信號競爭,因為這張圖僅反映了真實的協議狀態。

          附錄 D - XSD 模式

          BPEL4WS 模式

          <?xml version='1.0' encoding="UTF-8"?>
          <schema xmlns="http://www.w3.org/2001/XMLSchema"    
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:bpws="http://schemas.xmlsoap.org/ws/2002/07/business-process/" 
              targetNamespace="http://schemas.xmlsoap.org/ws/2002/07/business-process/" 
                  elementFormDefault="qualified">
          
              <import namespace="http://schemas.xmlsoap.org/wsdl/"/>
          
              <complexType name="tExtensibleElements">
                  <annotation>
                      <documentation>This type is extended by other component types to allow elements and attributres from other namespaces to be added. .</documentation>
                  </annotation>
                  <sequence>
                      <any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
                  </sequence>
                  <anyAttribute namespace="##other" processContents="lax"/>
          
              </complexType>
          
              <element name="process" type="bpws:tProcess"/>
              <complexType name="tProcess">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <sequence>
                              <element name="partners" type="bpws:tPartners" minOccurs="0"/>
                              <element name="containers" type="bpws:tContainers" minOccurs="0"/>
                              <element name="correlationSets" type="bpws:tCorrelationSets" minOccurs="0"/>
                              <element name="faultHandlers" type="bpws:tFaultHandlers" minOccurs="0"/>
                              <element name="compensationHandler" type="bpws:tCompensationHandler" minOccurs="0"/>
                              <group ref="bpws:activity"/>
                          </sequence>
                          <attribute name="name" type="NCName"/>
                          <attribute name="targetNamespace" type="anyURI"/>
                          <attribute name="suppressJoinFailure" type="bpws:tBoolean" default="no"/>
                          <attribute name="containerAccessSerializable" type="bpws:tBoolean" default="no"/>
                          <attribute name="enableInstanceCompensation" type="bpws:tBoolean" default="no"/>
                          <attribute name="abstractProcess" type="bpws:tBoolean" default="no"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <group name="activity">
                  <choice>
                      <element name="empty" type="bpws:tEmpty"/>
                      <element name="invoke" type="bpws:tInvoke"/>
                      <element name="receive" type="bpws:tReceive"/>
                      <element name="reply" type="bpws:tReply"/>
                      <element name="assign" type="bpws:tAssign"/>
                      <element name="wait" type="bpws:tWait"/>
                      <element name="throw" type="bpws:tThrow"/>
                      <element name="terminate" type="bpws:tTerminate"/>
                      <element name="flow" type="bpws:tFlow"/>
                      <element name="switch" type="bpws:tSwitch"/>
                      <element name="while" type="bpws:tWhile"/>
                      <element name="sequence" type="bpws:tSequence"/>
                      <element name="pick" type="bpws:tPick"/>
                      <element name="scope" type="bpws:tScope"/>
                  </choice>
              </group>
          
          
              <complexType name="tPartners">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <sequence>
                              <element name="partner" type="bpws:tPartner" minOccurs="1" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tPartner">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <attribute name="name" type="NCName" use="required"/>
                          <attribute name="serviceLinkType" type="QName" use="required"/>
                          <attribute name="myRole" type="NCName"/>
                          <attribute name="partnerRole" type="NCName"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tFaultHandlers">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <sequence>
                              <element name="catch" type="bpws:tCatch" minOccurs="0" maxOccurs="unbounded"/>
                              <element name="catchAll" type="bpws:tActivityOrCompensateContainer" minOccurs="0"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tCatch">
                  <complexContent>
                      <extension base="bpws:tActivityOrCompensateContainer">
                          <attribute name="faultName" type="QName" use="optional"/>
                          <attribute name="faultContainer" type="NCName" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
          
              <complexType name="tActivityContainer">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <sequence>
                              <group ref="bpws:activity"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
              <complexType name="tActivityOrCompensateContainer">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <choice>
                              <group ref="bpws:activity"/>
                              <element name="compensate" type="bpws:tCompensate"/>
                          </choice>
                      </extension>
                  </complexContent>
              </complexType>
          
          
              <complexType name="tOnMessage">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <sequence>
                              <element name="correlations" type="bpws:tCorrelations" minOccurs="0"/>
                              <group ref="bpws:activity"/>
                          </sequence>
                          <attribute name="partner" type="NCName" use="required"/>
                          <attribute name="portType" type="QName" use="required"/>
                          <attribute name="operation" type="NCName" use="required"/>
                          <attribute name="container" type="NCName" use="required"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tOnAlarm">
                  <complexContent>
                      <extension base="bpws:tActivityContainer">
                          <attribute name="for" type="bpws:tDuration-expr" use="optional"/>
                          <attribute name="until" type="bpws:tDeadline-expr" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tCompensationHandler">
                  <complexContent>
                      <extension base="bpws:tActivityOrCompensateContainer"/>
                  </complexContent>
              </complexType>
          
              <complexType name="tContainers">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <sequence>
                              <element name="container" type="bpws:tContainer" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tContainer">
                       
                          <!-- container does not allow extensibility elements           because otherwise its content model would be non-deterministic -->
                          <sequence>
                              <element name="message" type="wsdl:tMessage"
                                       minOccurs="0">
                                  <unique name="part">
                                       <selector xpath="wsdl:part"/>
                                       <field xpath="@name"/>
                                  </unique>
                              </element>
                          </sequence>
                          <attribute name="name" type="NCName" use="required"/>
                          <attribute name="messageType" type="QName" use="optional"/>
                          <anyAttribute namespace="##other" processContents="lax"/>
                  
          
              </complexType>
          
              <complexType name="tCorrelationSets">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
          
                          <sequence>
                              <element name="correlationSet" type="bpws:tCorrelationSet" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tCorrelationSet">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <attribute name="properties" use="required">
                              <simpleType>
                                  <list itemType="QName"/>
                              </simpleType>
                          </attribute>
                          <attribute name="name" type="NCName" use="required"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tActivity">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
          
                          <sequence>
                              <element name="target" type="bpws:tTarget" minOccurs="0" maxOccurs="unbounded"/>
                              <element name="source" type="bpws:tSource" minOccurs="0" maxOccurs="unbounded"/>
                          </sequence>
                          <attribute name="name" type="NCName" use="optional"/>
                          <attribute name="joinCondition" type="bpws:tBoolean-expr" use="optional"/>
                          <attribute name="suppressJoinFailure" type="bpws:tBoolean" use="optional"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tSource">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
          
                          <attribute name="linkName" type="NCName" use="required"/>
                          <attribute name="transitionCondition" type="bpws:tBoolean-expr" use="optional"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tTarget">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
          
                          <attribute name="linkName" type="NCName" use="required"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tEmpty">
                  <complexContent>
                      <extension base="bpws:tActivity"/>
                  </complexContent>
              </complexType>
          
              <complexType name="tCorrelations">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                         <sequence>
                      <element name="correlation" type="bpws:tCorrelation" minOccurs="1" maxOccurs="unbounded" />
                   </sequence>
                </extension>
             </complexContent>
             </complexType>
             <complexType name="tCorrelation">
                <complexContent>
                   <extension base="bpws:tExtensibleElements">
                          <attribute name="set" type="NCName" use="required"/>
                          <attribute name="initiation" type="bpws:tBoolean" use="optional" default="no"/>
                    <attribute name="pattern" use="optional">
                    <simpleType>
                      <restriction base="string">
                         <enumeration value="in" />
                         <enumeration value="out" />
                         <enumeration value="out-in" />
                      </restriction>
                    </simpleType>
                     </attribute>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tInvoke">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="correlations" type="bpws:tCorrelations"  minOccurs="0" maxOccurs="1"/>
                              <element name="catch" type="bpws:tCatch" minOccurs="0" maxOccurs="unbounded"/>
                              <element name="catchAll" type="bpws:tActivityOrCompensateContainer" minOccurs="0"/>
                              <element name="compensationHandler" type="bpws:tCompensationHandler" minOccurs="0"/>
                          </sequence>
                          <attribute name="partner" type="NCName" use="required"/>
                          <attribute name="portType" type="QName" use="required"/>
                          <attribute name="operation" type="NCName" use="required"/>
                          <attribute name="inputContainer" type="NCName" use="required"/>
                          <attribute name="outputContainer" type="NCName" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tReceive">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="correlations" type="bpws:tCorrelations" minOccurs="0"/>
                          </sequence>
                          <attribute name="partner" type="NCName" use="required"/>
                          <attribute name="portType" type="QName" use="required"/>
                          <attribute name="operation" type="NCName" use="required"/>
                          <attribute name="container" type="NCName" use="required"/>
                          <attribute name="createInstance" type="bpws:tBoolean" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tReply">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="correlations" type="bpws:tCorrelations" minOccurs="0"/>
                          </sequence>
                          <attribute name="partner" type="NCName" use="required"/>
                          <attribute name="portType" type="QName" use="required"/>
                          <attribute name="operation" type="NCName" use="required"/>
                          <attribute name="container" type="NCName" use="required"/>
                          <attribute name="faultName" type="QName" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tAssign">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="copy" type="bpws:tCopy" minOccurs="1" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tCopy">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
                          <sequence>
                              <element ref="bpws:from"/>
                              <element ref="bpws:to"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <element name="from" type="bpws:tFrom"/>
              <complexType name="tFrom">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
          
          
                          <attribute name="container" type="NCName"/>
                          <attribute name="part" type="NCName"/>
                          <attribute name="select" type="string"/>
                          <attribute name="property" type="QName"/>
                          <attribute name="partner" type="NCName"/>
                          <attribute name="expression" type="string"/>
                          <attribute name="opaque" type="bpws:tBoolean"/>
                      </extension>
                  </complexContent>
          
              </complexType>
              <element name="to">
                  <complexType>
                      <complexContent>
                          <restriction base="bpws:tFrom">
                              <attribute name="expression" type="string" use="prohibited"/>
                              <attribute name="opaque" type="bpws:tBoolean" use="prohibited"/>
                          </restriction>
                      </complexContent>
                  </complexType>
              </element>
              
              
              <complexType name="tWait">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <attribute name="for" type="bpws:tDuration-expr" use="optional"/>
                          <attribute name="until" type="bpws:tDeadline-expr" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tThrow">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <attribute name="faultName" type="QName" use="required"/>
                          <attribute name="faultContainer" type="NCName"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tCompensate">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <attribute name="scope" type="NCName" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tTerminate">
                  <complexContent>
                      <extension base="bpws:tActivity"/>
                  </complexContent>
              </complexType>
          
              <complexType name="tFlow">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="links" type="bpws:tLinks" minOccurs="0"/>
                              <group ref="bpws:activity" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tLinks">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <sequence>
                              <element name="link" type="bpws:tLink" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tLink">
                  <complexContent>
                      <extension base="bpws:tExtensibleElements">
                          <attribute name="name" type="NCName" use="required"/>
                      </extension>
                  </complexContent>
          
              </complexType>
          
              <complexType name="tSwitch">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="case" maxOccurs="unbounded">
                                  <complexType>
                                      <complexContent>
                                          <extension base="bpws:tActivityContainer">
                                              <attribute name="condition" type="bpws:tBoolean-expr" use="required"/>
                                          </extension>
                                      </complexContent>
                                  </complexType>
                              </element>
                              <element name="otherwise" type="bpws:tActivityContainer" minOccurs="0"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tWhile">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <group ref="bpws:activity"/>
                          </sequence>
                          <attribute name="condition" type="bpws:tBoolean-expr" use="required"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tSequence">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <group ref="bpws:activity" maxOccurs="unbounded"/>
                          </sequence>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tPick">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="onMessage" type="bpws:tOnMessage" maxOccurs="unbounded"></element>
                              <element name="onAlarm" type="bpws:tOnAlarm" minOccurs="0" maxOccurs="unbounded"/>
                          </sequence>
                          <attribute name="createInstance" type="bpws:tBoolean" use="optional"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <complexType name="tScope">
                  <complexContent>
                      <extension base="bpws:tActivity">
                          <sequence>
                              <element name="faultHandlers" type="bpws:tFaultHandlers" minOccurs="0"/>
                              <element name="compensationHandler" type="bpws:tCompensationHandler" minOccurs="0"/>
                              <group ref="bpws:activity"/>
                          </sequence>
                          <attribute name="containerAccessSerializable" type="bpws:tBoolean" use="required"/>
                      </extension>
                  </complexContent>
              </complexType>
          
              <simpleType name="tListOfNCNames">
                  <list itemType="NCName"/>
              </simpleType>
          
              <simpleType name="tBoolean-expr">
                  <restriction base="string"/>
              </simpleType>
          
              <simpleType name="tDuration-expr">
                  <restriction base="string"/>
              </simpleType>
          
              <simpleType name="tDeadline-expr">
                  <restriction base="string"/>
              </simpleType>
          
              <simpleType name="tBoolean">
                  <restriction base="string">
                      <enumeration value="yes"/>
                      <enumeration value="no"/>
                  </restriction>
              </simpleType>
          </schema>
          

          服務鏈接類型模式

          <?xml version='1.0' encoding="UTF-8"?>
          <schema xmlns="http://www.w3.org/2001/XMLSchema" 
             xmlns:slnk="http://schemas.xmlsoap.org/ws/2002/07/service-link/" 
             targetNamespace="http://schemas.xmlsoap.org/ws/2002/07/service-link/"
             elementFormDefault="qualified">
              
             <element name="serviceLinkType" type="slnk:tServiceLinkType"/>
                
             <complexType name="tServiceLinkType">
                <sequence>
                   <element name="role" type="slnk:tRole" minOccurs="1" maxOccurs="2"/>
                </sequence>
                <attribute name="name" type="NCName" use="required"/>
             </complexType>
             
             <complexType name="tRole">
                <sequence>
                   <element name="portType" minOccurs="1" maxOccurs="unbounded">
                      <complexType>
                         <attribute name="name" type="QName" use="required"/>
                      </complexType>
                   </element>
                </sequence>
                <attribute name="name" type="NCName" use="required"/>
             </complexType>
          </schema>
          

          服務引用模式

          <?xml version='1.0' encoding="UTF-8"?>
          <schema xmlns="http://www.w3.org/2001/XMLSchema" 
                  xmlns:sref="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
               xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
             targetNamespace="http://schemas.xmlsoap.org/ws/2002/07/service-reference/"
                elementFormDefault="qualified">
          
             <import namespace="http://schemas.xmlsoap.org/wsdl/"/> 
          
             <element name="serviceReference" type="sref:serviceReferenceType"/>
          
             <complexType name="serviceReferenceType">
                <sequence>
                   <element ref="wsdl:definitions" minOccurs="0"/>
                   <element name="service" type="QName"/>
                   <element name="referenceProperties" minOccurs="0">
                      <complexType>
                         <sequence>
                            <element name="property" type="sref:referencePropertyType" 
                                     maxOccurs="unbounded"/>
                         </sequence>
                      </complexType>
                   </element>
                </sequence>
             </complexType>
          
             <complexType name="referencePropertyType">
                <sequence>
                   <any namespace="##other" minOccurs="0"/>
                </sequence>
                <attribute name="name" type="QName"/>
             </complexType>
          </schema>
          

          消息屬性模式

          <?xml version='1.0' encoding="UTF-8"?>
          <schema xmlns="http://www.w3.org/2001/XMLSchema" 
              targetNamespace="http://schemas.xmlsoap.org/ws/2002/07/business-process/"           
                  xmlns:wsbp="http://schemas.xmlsoap.org/ws/2002/07/business-process/"
                  elementFormDefault="qualified">
           
              <element name="property">
                 <complexType>
                    <attribute name="name" type="NCName"/>
                    <attribute name="type" type="QName"/>
                 </complexType>
              </element>
          
              <element name="propertyAlias">
                 <complexType>
                    <attribute name="propertyName" type="QName" />
                    <attribute name="messageType" type="QName"/>
                    <attribute name="part" type="NCName"/>
                    <attribute name="select" type="string"/>
                 </complexType>
               </element>
          </schema>
          
          posted on 2006-05-30 15:21 海納百川,有容乃大 閱讀(977) 評論(0)  編輯  收藏 所屬分類: SOA

          <2025年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 万盛区| 镇沅| 迭部县| 滦平县| 诸城市| 舒城县| 山阳县| 赤壁市| 高邑县| 赣榆县| 贡觉县| 鹤岗市| 宜丰县| 科技| 平和县| 韶关市| 泸水县| 阳西县| 赣州市| 乡城县| 榕江县| 大洼县| 绍兴市| 永泰县| 霍城县| 新宾| 恩施市| 扎兰屯市| 朔州市| 澄江县| 徐闻县| 阿鲁科尔沁旗| 巴林右旗| 屯留县| 宝丰县| 和田市| 文水县| 湘阴县| 贵港市| 江安县| 桐梓县|