鷹翔宇空

          學習和生活

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            110 Posts :: 141 Stories :: 315 Comments :: 1 Trackbacks
          原文引自:http://www.oracle.com/technology/global/cn/pub/articles/matjaz_bpel1.html

          ??????????????????????????????????????????????????????????????????????????? BPEL 實例教程

          開發(fā)人員:J2EE 和 Web 服務

          BPEL 實例教程
          作者:Matjaz Juric

          了解如何創(chuàng)建一個將一系列虛擬的、與旅行相關(guān)的 web 服務結(jié)合起來的示例業(yè)務流程,然后將其部署到 Oracle BPEL Process Manager 運行時環(huán)境。

          本文相關(guān)下載
          示例代碼
          Oracle BPEL Process Manager 和 Designer

          面向 Web 服務的業(yè)務流程執(zhí)行語言(BPEL 或 BPEL4WS)是一種使用 Web 服務定義和執(zhí)行業(yè)務流程的語言。BPEL 使您可以通過組合、編排和協(xié)調(diào) Web 服務自上而下地實現(xiàn)面向服務的體系結(jié)構(gòu) (SOA)。BPEL 提供了一種相對簡單易懂的方法,可將多個 Web 服務組合到一個新的復合服務(稱作業(yè)務流程)中。

          本文將介紹如何創(chuàng)建一個將一系列虛擬的、與旅行相關(guān)的 web 服務結(jié)合起來的示例業(yè)務流程,然后將其部署到 Oracle BPEL Process Manager 運行時環(huán)境。

          BPEL 背景知識

          首先,介紹一些背景知識。BPEL 基于 XML 和 Web 服務構(gòu)建;它使用一種基于 Web 的語言,該語言支持 web 服務技術(shù)系列,包括 SOAP、WSDL、UDDI、Web 服務可靠性消息、Web 服務尋址、Web 服務協(xié)調(diào)以及 Web 服務事務。

          BPEL 代表了兩種早期工作流語言 - Web 服務流語言 (WSFL) 和 XLANG 的交匯。WSFL 由 IBM 基于有向圖概念設計。XLANG 是一種由 Microsoft 設計的塊結(jié)構(gòu)化語言。BPEL 組合了這兩種方法,并提供了豐富的詞匯來描述業(yè)務流程。

          BPEL 的第一個版本誕生于 2002 年 8 月。此后,隨著許多主要供應商(包括 Oracle)的紛紛加入了,催生了多項修改和改進,并于 2003 年 3 月推出了 1.1 版。2003 年 4 月,BPEL 提交結(jié)構(gòu)化信息標準促進組織 (OASIS) 以實現(xiàn)標準化,并組建了 Web 服務業(yè)務流程執(zhí)行語言技術(shù)委員會 (WSBPEL TC)。該努力使 BPEL 在業(yè)界獲得更廣范圍的認可。

          在企業(yè)內(nèi)部,BPEL 用于標準化企業(yè)應用程序集成以及將此集成擴展到先前孤立的系統(tǒng)。在企業(yè)之間,BPEL 使與業(yè)務合作伙伴的集成變得更容易、更高效。BPEL 激發(fā)企業(yè)進一步定義它們的業(yè)務流程,從而導致業(yè)務流程的優(yōu)化、重新設計以及選擇最合適的流程,進而實現(xiàn)了組織的進一步優(yōu)化。BPEL 中描述的業(yè)務流程定義并不影響現(xiàn)有系統(tǒng),因此對升級產(chǎn)生了促進作用。在已經(jīng)或?qū)⒁ㄟ^ Web 服務公開功能的環(huán)境中,BPEL 是一項重要的技術(shù)。隨著 Web 服務的不斷普及,BPEL 的重要性也隨之提高。

          編制與編排

          Web 服務通常公開某些應用程序或信息系統(tǒng)的操作。因此,組合多個 Web 服務實際上涉及基礎應用程序及其功能的集成。

          可以用兩種方式組合 Web 服務:

          • 編制
          • 編排

          在編制(通常用于專用業(yè)務流程)中,一個中央流程(可以是另一個 Web 服務)控制相關(guān)的 Web 服務并協(xié)調(diào)對操作所涉及 Web 服務的不同操作的執(zhí)行。相關(guān)的 Web 服務并不“知道”(也無需知道)它們參與了組合流程并在參與更高級別的業(yè)務流程。只有編制的中央?yún)f(xié)調(diào)員知道此目標,因此編制主要集中于操作的顯式定義以及 Web 服務的調(diào)用順序。(見圖 1。)

          圖 1
          圖 1:通過編制組合 Web 服務

          而編排并不依賴某個中央?yún)f(xié)調(diào)員。相反,編排所涉及的每個 Web 服務完全知道執(zhí)行其操作的時間以及交互對象。編排是一種強調(diào)在公共業(yè)務流程中交換消息的協(xié)作方式。編排的所有參與者都需要知道業(yè)務流程、要執(zhí)行的操作、要交換的消息以及消息交換的時間。(見圖 2。)

          圖 2
          圖 2:通過編排組合 Web 服務

          從組合 Web 服務以執(zhí)行業(yè)務流程的角度而言,編制是一個更靈活的范例,它相對于編排而言具有以下優(yōu)點:

          • 元件流程的協(xié)調(diào)由某個已知的協(xié)調(diào)員集中管理
          • 可以組合 Web 服務而不必使它們知道它們正在參與更大的業(yè)務流程
          • 可以準備其他方案以防發(fā)生故障。

          BPEL 支持兩種不同的業(yè)務流程描述方法(支持編制和編排):

          • 可執(zhí)行流程允許指定業(yè)務流程的準確細節(jié)。它們遵循編制范例,并可由編制引擎執(zhí)行。
          • 抽象業(yè)務協(xié)議允許只指定雙方之間的公共消息交換。它們不包含流程的內(nèi)部細節(jié)并且無法執(zhí)行。它們遵循編排范例。

          現(xiàn)在,我們來逐步演示如何創(chuàng)建可執(zhí)行的 BPEL 業(yè)務流程;可以下載它的代碼并將其部署到 Oracle BPEL Process Manager。我們將假設已經(jīng)按照安裝指導成功安裝了 Oracle BPEL Process Manager,并假設它使用缺省端口 9700。如果在安裝過程中選擇了其他端口,則必須相應地修改示例。

          構(gòu)建業(yè)務流程

          BPEL 流程指定參與的 Web 服務的確切調(diào)用順序 - 順序地或并行地。使用 BPEL,您可以表述條件行為。例如,某個 Web 服務的調(diào)用可以取決于上次調(diào)用的值。還可以構(gòu)造循環(huán)、聲明變量、復制和賦予值、定義故障處理程序等。通過組合所有這些構(gòu)造,您可以以算法的形式定義復雜業(yè)務流程。實際上,由于業(yè)務流程本質(zhì)上屬于活動圖,因此使用統(tǒng)一建模語言 (UML) 活動圖表示它們可能很有用。

          通常情況下,BPEL 業(yè)務流程接收請求。為了滿足請求,該流程調(diào)用相關(guān)的 Web 服務,然后響應原始調(diào)用方。由于 BPEL 流程與其他 Web 服務通信,因此它在很大程度上依賴于復合型 Web 服務調(diào)用的 Web 服務 的 WSDL 描述。

          我們來看一個示例。一個 BPEL 流程由多個步驟組成,每個步驟稱作“活動”。BPEL 支持基元活動和結(jié)構(gòu)活動。基元活動表示基本構(gòu)造,用于如下所示的常見任務:

          • 使用 <invoke> 調(diào)用其他 Web 服務
          • 使用 <receive>(接收請求)等待客戶端通過發(fā)送消息調(diào)用業(yè)務流程
          • 使用 <reply> 生成同步操作的響應
          • 使用 <assign> 操作數(shù)據(jù)變量
          • 使用 <throw> 指示故障和異常
          • 使用 <wait> 等待一段時間
          • 使用 <terminate> 終止整個流程。
          然后,我們可以組合這些基元活動以及其他基元活動,以定義準確指定業(yè)務流程步驟的復雜算法。為組合基元活動,BPEL 支持幾個結(jié)構(gòu)活動。其中最重要的是:

          • 順序 (<sequence>),它允許定義一組將按順序調(diào)用的活動。
          • 流 (<flow>),用于定義一組將并行調(diào)用的活動
          • Case-switch 構(gòu)造 (<switch>),用于實現(xiàn)分支
          • While (<while>),用于定義循環(huán)
          • 使用 <pick> 能夠選擇多個替換路徑之一。

          每個 BPEL 業(yè)務還將使用 <partnerLink> 定義合作伙伴鏈接,使用 <variable> 聲明變量。

          為了理解 BPEL 是如何描述業(yè)務流程的,我們將定義雇員出差安排的簡化業(yè)務流程:客戶端調(diào)用此業(yè)務流程,指定雇員姓名、目的地、出發(fā)日期以及返回日期。此 BPEL 業(yè)務流程首先檢查雇員出差狀態(tài)。我們將假設存在一個可用于進行此類檢查的 Web 服務。然后,此 BPEL 流程將檢查以下兩家航空公司的機票價格:美國航空公司和達美航空公司。我們將再次假設這兩家航空公司均提供了可用于進行此類檢查的 Web 服務。最后,此 BPEL 流程將選擇較低的價格并將出差計劃返回給客戶端。

          然后,我們將構(gòu)建一個異步 BPEL 流程。我們將假設用于檢查雇員出差狀態(tài)的 Web 服務是同步的。由于可以立即獲取此數(shù)據(jù)并將其返回給調(diào)用方,因此這是一個合理的方法。為了獲取機票價格,我們使用異步調(diào)用。由于確認飛機航班時刻表可能需要稍長的時間,因此這也是一個合理的方法。為簡化示例,我們假設以上兩家航空公司均提供了 Web 服務,且這兩個 Web 服務完全相同(即提供相同的端口類型和操作)。

          在實際情形下,您通常無法選擇 Web 服務,而是必須使用您的合作伙伴提供的服務。如果您有幸能夠同時設計 Web 服務和 BPEL 流程,則應考慮用哪個接口更好。通常,您將對持續(xù)時間較長的操作使用異步服務,而對在相對較短的時間內(nèi)返回結(jié)果的操作使用同步服務。如果使用異步 Web 服務,則 BPEL 流程通常也是異步的。

          當您用 BPEL 定義業(yè)務流程時,您實際上定義了一個由現(xiàn)有服務組成的新 Web 服務。該新 BPEL 復合 Web 服務的接口使用一組端口類型來提供類似任何其他 Web 服務的操作。要調(diào)用用 BPEL 描述的業(yè)務流程,則必須調(diào)用生成的復合 Web 服務。圖 3 是我們流程的示意圖。

          圖 3
          圖 3:出差安排示例 BPEL 流程

          在開發(fā)此示例 BPEL 流程的過程中,您將經(jīng)歷下列步驟:

          • 熟悉相關(guān)的 Web 服務
          • 為此 BPEL 流程定義 WSDL
          • 定義合作伙伴鏈接類型
          • 開發(fā)此 BPEL 流程:
            • 定義合作伙伴鏈接
            • 聲明變量
            • 編寫流程邏輯定義。

          第 1 步:列出相關(guān) Web 服務的清單

          在您開始編寫 BPEL 流程定義之前,必須先熟悉從業(yè)務流程中調(diào)用的 Web 服務。這些服務稱作合作伙伴 Web 服務。本示例使用雇員出差狀態(tài) Web 服務以及美國航空公司和達美航空公司 Web 服務(這兩個 Web 服務具有相同的 WSDL 描述)。(同樣,本示例中使用的 Web 服務是虛構(gòu)的。)

          雇員出差狀態(tài) Web 服務雇員出差狀態(tài) Web 服務提供 EmployeeTravelStatusPT 端口類型,通過它可以使用 EmployeeTravelStatus 操作檢查雇員出差狀態(tài)。此操作將返回雇員可以使用的乘機標準(可能為經(jīng)濟艙、商務艙或頭等艙)。(見圖 4。)

          圖 4
          圖 4:雇員出差狀態(tài) Web 服務

          航空公司 Web 服務航空公司 Web 服務是異步的;因此它指定了兩個端口類型:第一個端口類型 FlightAvailabilityPT 用于使用 FlightAvailability 操作檢查航班可用性。為返回結(jié)果,該 Web 服務指定了第二個端口類型 FlightCallbackPT。此端口類型指定 FlightTicketCallback 操作。

          盡管航空公司 Web 服務定義了兩個端口類型,但它只實現(xiàn) FlightAvailabilityPT。FlightCallbackPT 則由作為 Web 服務客戶端的 BPEL 流程實現(xiàn)。圖 5 是此 Web 服務體系結(jié)構(gòu)的示意圖:

          圖 5
          圖 5:航空公司 Web 服務

          第 2 步:為 BPEL 流程定義 WSDL

          接下來,我們必須將此業(yè)務出差 BPEL 公開為 Web 服務。因此,第二步是為它定義 WSDL。此流程將必須從它的客戶端接收消息并返回結(jié)果。它必須公開 TravelApprovalPT 端口類型,后者將指定一個輸入消息。它還必須聲明 ClientCallbackPT 端口類型(用于使用回調(diào)將結(jié)果異步返回給客戶端)。圖 6 說明了此流程。

          圖 6
          圖 6:此 BPEL 流程的 WSDL

          第 3 步:定義合作伙伴鏈接類型

          第三步是定義合作伙伴鏈接類型。合作伙伴鏈接類型表示 BPEL 流程與相關(guān)方(包括 BPEL 流程調(diào)用的 Web 服務以及調(diào)用 BPEL 流程的客戶端)之間的交互。

          本示例包含三個不同的合作伙伴:客戶端、雇員出差狀態(tài)服務和航空公司服務。理想情況下,每個 Web 服務都應在 WSDL 中定義相應的合作伙伴鏈接類型。(實際情形可能不是這樣的。)然后,我們可以使用 WSDL 包裝合作伙伴 Web 服務(導入 Web 服務的 WSDL 并定義合作伙伴鏈接類型)?;蛘?,我們可以在 BPEL 流程的 WSDL 中定義所有合作伙伴鏈接。但由于此方法違反了封裝原則,因此不建議使用。

          對于本示例,我們定義了三個合作伙伴鏈接類型(每個類型位于 Web 服務的相應 WSDL 中):

          • travelLT:用于描述此 BPEL 流程客戶端與此 BPEL 流程本身之間的交互。此交互是異步交互。此合作伙伴鏈接類型在此 BPEL 流程的 WSDL 中定義。
          • employeeLT:用于描述此 BPEL 流程與雇員出差狀態(tài) Web 服務之間的交互。此交互是同步交互。此合作伙伴鏈接類型在雇員 Web 服務的 WSDL 中定義。
          • flightLT:描述此 BPEL 流程與航空公司 Web 服務之間的交互。此交互是異步交互,且航空公司 Web 服務對此 BPEL 流程調(diào)用一個回調(diào)。此合作伙伴鏈接類型在航空公司 Web 服務的 WSDL 中定義。

          每個合作伙伴鏈接可以擁有一個或兩個角色,我們必須為每個角色指定它使用的 portType。對于同步操作,由于操作只是單向調(diào)用,因此每個合作伙伴鏈接類型僅有一個角色。例如,此 BPEL 流程對雇員出差狀態(tài) Web 服務調(diào)用 EmployeeTravelStatus 操作。由于它是同步操作,因此此 BPEL 流程等待完成并僅在完成操作后取得響應。

          對于異步回調(diào)操作,我們必須指定兩個角色。第一個角色描述客戶端操作調(diào)用。第二個角色描述回調(diào)操作調(diào)用。在本示例中,BPEL 流程與航空公司 Web 服務之間存在一個異步關(guān)系。

          正如我們已經(jīng)指出的,我們需要三個合作伙伴鏈接類型:兩個鏈接類型指定兩個角色(因為它們是異步的),一個鏈接類型指定一個角色(因為它是同步的)。

          合作伙伴鏈接類型在特殊命名空間http://schemas.xmlsoap.org/ws/2003/05/partner-link/ 的 WSDL 定義。首先,我們在客戶端使用的 BPEL 流程 WSDL 中定義 travelLT 鏈接類型以調(diào)用此 BPEL 流程。所需的第一個角色是出差服務(即,我們的 BPEL 流程)的角色。客戶端使用 TravelApprovalPT 端口類型與此 BPEL 服務通信。第二個角色 travelServiceCustomer 描述了此 BPEL 流程將在 ClientCallbackPT 端口類型中對其執(zhí)行回調(diào)的客戶端的特征:

          <plnk:partnerLinkType name="travelLT">
          
          <plnk:role name="travelService">
          <plnk:portType name="tns:TravelApprovalPT" />
          </plnk:role>
          
          <plnk:role name="travelServiceCustomer">
          <plnk:portType name="tns:ClientCallbackPT" />
          </plnk:role>
          
          </plnk:partnerLinkType>
          

          第二個鏈接類型是 employeeLT。它用于描述此 BPEL 流程與雇員出差狀態(tài) Web 服務之間的通信,并在此雇員 Web 服務的 WSDL 中定義。此交互是同步交互,因此我們需要一個名為 employeeTravelStatusService 的角色。此 BPEL 流程使用雇員 Web 服務上的 EmployeeTravelStatusPT

          <plnk:partnerLinkType name="employeeLT">
          
          <plnk:role name="employeeTravelStatusService">
          <plnk:portType name="tns:EmployeeTravelStatusPT" />
          </plnk:role>
          
          </plnk:partnerLinkType>
          

          最后一個合作伙伴鏈接類型 flightLT 用于描述此 BPEL 流程與航空公司 Web 服務之間的通信。此通信是異步通信。此 BPEL 流程對航空公司 Web 服務調(diào)用一個異步操作。此 Web 服務在完成請求后對此 BPEL 流程調(diào)用一個回調(diào)。因此,我們需要兩個角色。第一個角色描述航空公司 Web 服務對于此 BPEL 流程服務的角色,即航空公司服務 (airlineService)。此 BPEL 流程使用 FlightAvailabilityPT 端口類型進行異步調(diào)用。第二個角色描述了此 BPEL 流程對于航空公司 Web 服務的角色。對于航空公司 Web 服務而言,此 BPEL 流程是一個航空公司客戶,因此角色名稱為 airlineCustomer。航空公司 Web 服務使用 FlightCallbackPT 端口類型進行回調(diào)。此合作伙伴鏈接類型在航空公司 Web 服務的 WSDL 中定義:

          <plnk:partnerLinkType name="flightLT">
          
          <plnk:role name="airlineService">
          <plnk:portType name="tns:FlightAvailabilityPT" />
          </plnk:role>
          
          <plnk:role name="airlineCustomer">
          <plnk:portType name="tns:FlightCallbackPT" />
          </plnk:role>
          
          </plnk:partnerLinkType>
          

          了解合作伙伴鏈接類型對于開發(fā) BPEL 流程規(guī)范至關(guān)重要。有時,它可以幫助生成所有交互的圖表。定義合作伙伴鏈接類型后,我們已經(jīng)完成了準備階段,并準備開始編寫業(yè)務流程定義。

          第 4 步:創(chuàng)建業(yè)務流程

          現(xiàn)在,您就可以開始編寫 BPEL 流程了。通常,BPEL 流程等待客戶端傳入的消息,以啟動業(yè)務流程的執(zhí)行。在本示例中,客戶端通過發(fā)送輸入消息TravelRequest 啟動此 BPEL 流程。然后,此 BPEL 流程通過發(fā)送 EmployeeTravelStatusRequest 消息調(diào)用雇員出差狀態(tài) Web 服務。由于此調(diào)用是同步調(diào)用,因此它等待 EmployeeTravelStatusResponse 消息。然后,此 BPEL 流程通過向上述兩家航空公司 Web 服務發(fā)送 FlightTicketRequest 消息對它們進行并發(fā)異步調(diào)用。每個航空公司 Web 服務通過發(fā)送 TravelReponse 消息進行回調(diào)。然后,此 BPEL 流程選擇較合適的航空公司并使用 TravelResponse 消息對客戶端進行回調(diào)。

          我們首先編寫一個空的 BPEL 流程提綱,它展示了每個 BPEL 流程定義文檔的基本結(jié)構(gòu):

          <process name="BusinessTravelProcess" ... >
             
          <partnerLinks>
          <!-- The declaration of partner links -->
          </partnerLinks>
          
          <variables>
          <!-- The declaration of variables -->
          </variables>
          
          <sequence>
          <!-- The definition of the BPEL business process main body -->
          </sequence>
          
          </process>
          

          我們首先添加所需的命名空間。此處,我們必須定義目標命名空間以及用于訪問雇員和航空公司 WSDL 以及此 BPEL 流程 WSDL 的命名空間。我們還必須為所有 BPEL 活動標記聲明命名空間(此處采用缺省命名空間,以便不必限定每個 BPEL 標記名)。BPEL 活動命名空間必須為 http://schemas.xmlsoap.org/ws/2003/03/business-process/:

          <process name="BusinessTravelProcess" 
          targetNamespace="http://packtpub.com/bpel/travel/" 
          xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
          xmlns:trv="http://packtpub.com/bpel/travel/"
          xmlns:emp="http://packtpub.com/service/employee/"
          xmlns:aln="http://packtpub.com/service/airline/" >
          ...
          

          合作伙伴鏈接接下來,我們必須定義合作伙伴鏈接,它們定義與此 BPEL 流程交互的不同方。每個合作伙伴鏈接都與描述其特性的特定 partnerLinkType 相關(guān)。每個合作伙伴鏈接還最多指定兩個屬性:

          • myRole:表明業(yè)務流程本身的角色。
          • partnerRole:表明合作伙伴的角色。

          合作伙伴鏈接僅可以指定一個角色,通常同步請求/響應操作也僅能指定一個角色。對于異步操作,它指定兩個角色。在本示例中,我們定義四個角色。第一個合作伙伴鏈接稱作客戶端,由 travelLT 合作伙伴鏈接類型描述其特性。此客戶端調(diào)用該業(yè)務流程。我們需要指定 myRole 屬性以描述此 BPEL 流程 (travelService) 的角色。我們必須指定第二個角色:partnerRole。此處,該角色為 travelServiceCustomer,它描述 BPEL 流程客戶端的特性。

          第二個合作伙伴鏈接稱作 employeeTravelStatus,由 employeeLT 合作伙伴鏈接類型描述其特性。它是 BPEL 流程與 Web 服務之間的一個同步請求/響應關(guān)系;我們再次僅指定一個角色。此時,該角色為 partnerRole,這是因為我們描述了 Web 服務(它是此 BPEL 流程的合作伙伴)的角色:

          最后兩個合作伙伴鏈接對應于航空公司 Web 服務。由于它們使用同一類型的 Web 服務,因此我們基于一個合作伙伴鏈接類型 flightLT 指定兩個合作伙伴鏈接。此處,由于我們使用異步回調(diào)通信,因此需要兩個角色。此 BPEL 流程 (myRole) 對于航空公司 Web 服務的角色為 airlineCustomer,而航空公司 (partnerRole) 的角色為 airlineService

          <partnerLinks>
          <partnerLink name="client" 
          partnerLinkType="trv:travelLT"
          myRole="travelService"
          partnerRole="travelServiceCustomer"/>
          
          <partnerLink name="employeeTravelStatus" 
          partnerLinkType="emp:employeeLT"
          partnerRole="employeeTravelStatusService"/>
          
          <partnerLink name="AmericanAirlines" 
          partnerLinkType="aln:flightLT"
          myRole="airlineCustomer"
          partnerRole="airlineService"/>
                             
          <partnerLink name="DeltaAirlines" 
          partnerLinkType="aln:flightLT"
          myRole="airlineCustomer"
          partnerRole="airlineService"/>
          </partnerLinks>
          

          變量 BPEL 流程中的變量用于存儲消息以及對這些消息進行重新格式化和轉(zhuǎn)換。您通常需要為發(fā)送到合作伙伴以及從合作伙伴收到的每個消息定義一個變量。就我們的流程而言,我們需要七個變量。我們將它們命名為 TravelRequest、EmployeeTravelStatusRequest、EmployeeTravelStatusResponse、FlightDetails、FlightResponseAA、FlightResponseDATravelResponse

          我們必須為每個變量指定類型??梢允褂?WSDL 消息類型、XML 模式簡單類型或 XML 模式元素。在我們的示例中,我們對所有變量使用 WSDL 消息類型:

          <variables>
          <!-- input for this process -->      
          <variable name="TravelRequest" 
          messageType="trv:TravelRequestMessage"/>
          <!-- input for the Employee Travel Status web service -->
          <variable name="EmployeeTravelStatusRequest" 
          messageType="emp:EmployeeTravelStatusRequestMessage"/>
          <!-- output from the Employee Travel Status web service -->
          <variable name="EmployeeTravelStatusResponse" 
          messageType="emp:EmployeeTravelStatusResponseMessage"/>
          <!-- input for American and Delta web services -->
          <variable name="FlightDetails" 
          messageType="aln:FlightTicketRequestMessage"/>
          <!-- output from American Airlines -->
          <variable name="FlightResponseAA" 
          messageType="aln:TravelResponseMessage"/>
          <!-- output from Delta Airlines -->
          <variable name="FlightResponseDA" 
          messageType="aln:TravelResponseMessage"/>
          <!-- output from BPEL process -->
          <variable name="TravelResponse" 
          messageType="aln:TravelResponseMessage"/>
          </variables>
          

          BPEL 流程主體流程主體指定調(diào)用合作伙伴 Web 服務的順序。它通常以 <sequence>(用于定義多個將按順序執(zhí)行的操作)開始。在順序中,我們首先指定啟動業(yè)務流程的輸入消息。我們使用 <receive> 構(gòu)造(它等待匹配消息,在本示例中為 TravelRequest 消息)實現(xiàn)此目的。在 <receive> 構(gòu)造中,我們不直接指定消息。而是指定合作伙伴鏈接、端口類型、操作名稱以及可選變量(用于保存收到的消息以用于隨后的操作)。

          我們將消息接收與客戶端合作伙伴鏈接在一起,并等待對端口類型 TravelApprovalPT 調(diào)用 TravelApproval 操作。我們將收到的消息存儲到 TravelRequest 變量中:

          <sequence>
          
          <!-- Receive the initial request for business travel from client -->
          <receive partnerLink="client" 
          portType="trv:TravelApprovalPT" 
          operation="TravelApproval" 
          variable="TravelRequest"
          createInstance="yes" />
          ...
          

          <receive> 等待客戶端調(diào)用 TravelApproval 操作,并將傳入的消息以及有關(guān)業(yè)務出差的參數(shù)存儲到 TravelRequest 變量中。此處,此變量名與消息名相同,但并不一定要相同。

          接下來,我們需要調(diào)用雇員出差狀態(tài) Web 服務。但在調(diào)用之前,我們必須為此 Web 服務準備輸入。查看雇員 Web 服務的 WSDL,可以看到我們必須發(fā)送由雇員部分組成的消息。我們可以通過復制客戶端發(fā)送的消息的雇員部分來構(gòu)造此消息。編寫相應的賦值語句:

          ...
          <!-- Prepare the input for the Employee Travel Status Web Service -->
          <assign>
          <copy>
          <from variable="TravelRequest" part="employee"/>
          <to variable="EmployeeTravelStatusRequest" part="employee"/>
          </copy>
          </assign>
          ...
          

          現(xiàn)在,我們就可以調(diào)用雇員出差狀態(tài) Web 服務了。為了進行同步調(diào)用,我們使用 <invoke> 活動。我們使用 employeeTravelStatus 合作伙伴鏈接,并對 EmployeeTravelStatusPT 端口類型調(diào)用 EmployeeTravelStatus 操作。我們已經(jīng)在 EmployeeTravelStatusRequest 變量中準備了輸入消息。由于它是同步調(diào)用,因此該調(diào)用等待回應并將其存儲在 EmployeeTravelStatusResponse 變量中:

          ...
          <!-- Synchronously invoke the Employee Travel Status Web Service -->
          <invoke partnerLink="employeeTravelStatus" 
          portType="emp:EmployeeTravelStatusPT" 
          operation="EmployeeTravelStatus"
          inputVariable="EmployeeTravelStatusRequest" 
          outputVariable="EmployeeTravelStatusResponse" />
          ...
          

          下一步是調(diào)用上述兩個航空公司 Web 服務。同樣,我們先準備所需的輸入消息(這兩個 Web 服務的輸入消息相同)。FlightTicketRequest 消息包含兩部分:

          • flightData:它從客戶端消息 (TravelRequest) 中檢索而得。
          • travelClass:它從 EmployeeTravelStatusResponse 變量中檢索而得。

          因此,我們編寫一個包含兩個 copy 元素的賦值:

          ...
          <!-- Prepare the input for AA and DA -->
          <assign>
          <copy>
          <from variable="TravelRequest" part="flightData"/>
          <to variable="FlightDetails" part="flightData"/>
          </copy>
          <copy>
          <from variable="EmployeeTravelStatusResponse" part="travelClass"/>
          <to variable="FlightDetails" part="travelClass"/>
          </copy>
          </assign>
          ...
          

          輸入數(shù)據(jù)包含需要傳遞給航空公司 Web 服務的數(shù)據(jù)。由于格式相同,因此我們可以使用一個簡單復制直接傳遞它。在實際情況下,通常需要執(zhí)行轉(zhuǎn)換。為此,可以使用具有 <assign> 的 XPath 表達式、使用轉(zhuǎn)換服務(如 XSLT 引擎)或使用由特定 BPEL 服務器提供的轉(zhuǎn)換功能。

          現(xiàn)在,我們準備調(diào)用這兩個航空公司 Web 服務。我們將進行并發(fā)的異步調(diào)用。為表述并發(fā),BPEL 提供了 <flow> 活動。對每個 Web 服務的調(diào)用將包含兩個步驟:

          • 使用 <invoke> 活動進行異步調(diào)用。
          • 使用 <receive> 活動等待回調(diào)。

          我們使用 <sequence> 對這兩個活動進行分組。這兩個調(diào)用只在合作伙伴鏈接名稱上存在差別。我們對一個調(diào)用使用 AmericanAirlines,對另一個調(diào)用使用 DeltaAirlines。兩者均對 FlightAvailabilityPT 端口類型調(diào)用 FlightAvailability 操作,發(fā)送 FlightDetails 變量中的消息。

          使用 <receive> 活動接收回調(diào)。我們再次使用這兩個合作伙伴鏈接名。<receive> 等待對 FlightCallbackPT 端口類型調(diào)用 FlightTicketCallback 操作。我們將結(jié)果消息分別存儲到 FlightResponseAAFlightResponseDA 變量中:

          ...
          <!-- Make a concurrent invocation to AA in DA -->
          <flow>
                
          <sequence>
          <!-- Async invoke of the AA web service and wait for the callback-->
                  
          <invoke partnerLink="AmericanAirlines" 
          portType="aln:FlightAvailabilityPT" 
          operation="FlightAvailability"
          inputVariable="FlightDetails" />
          
          <receive partnerLink="AmericanAirlines" 
          portType="aln:FlightCallbackPT" 
          operation="FlightTicketCallback"
          variable="FlightResponseAA" />
          
          </sequence>
          
          <sequence>
          <!-- Async invoke of the DA web service and wait for the callback-->
                  
          <invoke partnerLink="DeltaAirlines" 
          portType="aln:FlightAvailabilityPT" 
          operation="FlightAvailability"
          inputVariable="FlightDetails" />
          
          <receive partnerLink="DeltaAirlines" 
          portType="aln:FlightCallbackPT" 
          operation="FlightTicketCallback"
          variable="FlightResponseDA" />
          
          </sequence>
          
          </flow>
          ...
          

          在該流程的這個階段,我們收到兩個機票報價。在下一步中,我們必須選擇一個機票報價。為此,我們使用 <switch> 活動。

          ...
          <!-- Select the best offer and construct the TravelResponse -->
          <switch>
                        
          <case condition="bpws:getVariableData('FlightResponseAA',
          'confirmationData','/confirmationData/Price') 
          <= bpws:getVariableData('FlightResponseDA',
          'confirmationData','/confirmationData/Price')">
                              
          <!-- Select American Airlines -->
          <assign>
          <copy>
          <from variable="FlightResponseAA" />
          <to variable="TravelResponse" />
          </copy>
          </assign>
          </case>
                              
          <otherwise>
          <!-- Select Delta Airlines -->
          <assign>
          <copy>
          <from variable="FlightResponseDA" />
          <to variable="TravelResponse" />
          </copy>
          </assign>
          </otherwise>
          </switch>
          ...
          

          <case> 元素中,我們檢查美國航空公司的機票報價 (FlightResponseAA) 是等于還是低于達美航空公司的機票報價 (FlightResponseDA)。為此,我們使用 BPEL 函數(shù) getVariableData 并指定變量名。價格位于 confirmationData 消息的內(nèi)部,雖然它是唯一的消息部分,但我們?nèi)员仨氈付ㄋ?。我們還必須指定查詢表達式以找到價格元素。此處,我們采用簡單的 XPath 1.0 表達式。

          如果美國航空公司的機票報價低于達美航空公司的機票報價,則將 FlightResponseAA 變量復制到 TravelResponse 變量(我們最終將此變量返回給客戶端)。否則,我們將復制 FlightResponseDA 變量。

          我們已經(jīng)到達此 BPEL 業(yè)務流程的最后一步 — 使用 <invoke> 活動將回調(diào)返回給客戶端。對于此回調(diào),我們使用客戶端合作伙伴鏈接并對 ClientCallbackPT 端口類型調(diào)用 ClientCallback 操作。保存答復消息的變量為 TravelResponse

          ...
          <!-- Make a callback to the client -->
          <invoke partnerLink="client" 
          portType="trv:ClientCallbackPT" 
          operation="ClientCallback"
          inputVariable="TravelResponse" />
          </sequence>
          
          </process>
          

          后續(xù)步驟

          下載用于 Web 服務的業(yè)務流程執(zhí)行語言 一書中的示例章節(jié)。

          訪問 Web 服務技術(shù)中心

          到此,我們已經(jīng)完成了我們的第一個 BPEL 業(yè)務流程規(guī)范。您可以看到,BPEL 并不是很復雜,并允許相對簡單和自然的業(yè)務流程規(guī)范。

          第 5 步:部署和測試

          我們部署到 Oracle BPEL Process Manager 的每個 BPEL 流程都需要一個流程描述符。BPEL 標準不包括此流程描述符,且它特定于 BPEL 服務器。部署流程描述符是流程在給定平臺上的唯一實現(xiàn)部分,必須重寫它才能在不同 BPEL 引擎上運行該流程。Oracle 流程描述符是一個 XML 文件,它指定有關(guān) BPEL 流程的以下細節(jié):BPEL 源文件名、BPEL 流程名 (ID)、所有合作伙伴鏈接 WSDL Web 服務的 WSDL 位置以及可選的配置屬性。流程描述符的默認文件名為 bpel.xml,但我們可以使用任何其他名稱:

          <BPELSuitcase>
          
          <BPELProcess src="Travel.bpel" id="TravelProcessCh4">
          <partnerLinkBindings>
          
          <partnerLinkBinding name="client">
          <property name="wsdlLocation">
          Travel.wsdl
          </property>
          </partnerLinkBinding>
          
          <partnerLinkBinding name="employeeTravelStatus">
          <property name="wsdlLocation">
          http://localhost:9700/orabpel/default/Employee/Employee?wsdl
          </property>
          </partnerLinkBinding>
          
          <partnerLinkBinding name="AmericanAirlines">
          <property name="wsdlLocation">
          http://localhost:9700/orabpel/default/AmericanAirline/AmericanAirline?wsdl
          </property>
          </partnerLinkBinding>
          
          <partnerLinkBinding name="DeltaAirlines">
          <property name="wsdlLocation">
          http://localhost:9700/orabpel/default/DeltaAirline/DeltaAirline?wsdl
          </property>
          </partnerLinkBinding>
          
          </partnerLinkBindings>
          </BPELProcess>
          </BPELSuitcase>
          

          我們現(xiàn)在準備啟動 BPEL Process Manager。可以從開始菜單(如果使用 Windows)或通過執(zhí)行 c:\orabpel\bin 目錄中的 startOraBPEL 腳本(假設 Oracle BPEL Process Manager 已經(jīng)安裝到 c:\orabpel 中)來執(zhí)行此操作。為便于訪問,建議將此目錄包含在 PATH 中。

          Oracle BPEL Process Manager 包含一個名為 obant 的 Ant 實用程序,用于配置復雜的編譯和部署方案。obant 只是一個圍繞標準 Ant 的包裝程序,用于設置環(huán)境,然后調(diào)用標準 Ant Java 任務。要使用它,我們必須準備相應的項目文件(通常名為 build.xml)。以下是出差示例流程的項目文件:

          <?xml version="1.0"?>
          <project name="TravelProcessCh4" default="main" basedir=".">
          
          <property name="deploy" value="default"/>
          <property name="rev" value="1.0"/>
                 
          <target name="main">
          <bpelc home="${home}" rev="${rev}" deploy="${deploy}"/>        
          </target>
          
          </project>
          

          要編譯和部署此 BPEL 流程,我們只需從命令行啟動 obant。

          既然我們已經(jīng)在 Oracle BPEL 服務器上成功部署了 BPEL 流程,那我們就執(zhí)行它。Oracle BPEL Process Manager 提供了一個 BPEL 控制臺,通過它可以在 BPEL 服務器域中執(zhí)行、監(jiān)視、管理和調(diào)試 BPEL 流程??梢酝ㄟ^ http://localhost:9700/BPELConsole/ 訪問 BPEL 控制臺。我們必須單擊流程名、填寫以下表單并按 Post XML Message 按鈕:

          圖 7
          圖 7:BPEL 控制臺

          我們現(xiàn)在看到一個屏幕,通知我們正在異步處理流程實例。我們可以選擇執(zhí)行、實例審計或?qū)嵗{(diào)試的可視化流。實例的可視化流以圖形方式顯示了 BPEL 流程實例的執(zhí)行。我們可以監(jiān)視流程的執(zhí)行及其狀態(tài)(正在運行、已完成、已取消或過時):

          圖 8
          圖 8:實例流的圖形視圖

          Oracle BPEL Process Manager 提供了多個用于審計、管理、調(diào)試和部署 BPEL 流程的選項。有關(guān)更多信息,請查看產(chǎn)品文檔

          結(jié)論

          現(xiàn)在,您已經(jīng)熟悉了使用 BPEL 組合 Web 服務的基本概念,您可以更深入地研究更高級的概念。我的下一篇文章將介紹一些高級 BPEL 特性,如故障處理、范圍、補償、并發(fā)活動以及事件處理。

          Matjaz B. Juric 擁有計算機與信息科學的博士學位。他是用于 Web 服務的業(yè)務流程執(zhí)行語言一書 (Packt Publishing) 的作者。Matjaz 還是專家級 J2EE EAI、專家級 EJB、應用的 J2EE 設計模式以及VB.NET 序列化指南(全部由 Wrox Press 出版)的合著者。Matjaz 還曾為 Java Developer's Journal、Java Report、Java World 以及其他出版物撰寫過文章。

          posted on 2006-04-12 09:56 TrampEagle 閱讀(3659) 評論(0)  編輯  收藏 所屬分類: web
          主站蜘蛛池模板: 西青区| 石城县| 佛山市| 呼伦贝尔市| 石柱| 出国| 萝北县| 将乐县| 隆子县| 东辽县| 洱源县| 盘锦市| 甘孜县| 水城县| 织金县| 凉城县| 文登市| 津市市| 喜德县| 平武县| 邻水| 叶城县| 鄄城县| 长垣县| 隆回县| 离岛区| 平乡县| 新乐市| 台南市| 河池市| 嘉兴市| 祁阳县| 寿阳县| 岐山县| 慈利县| 桃园市| 神农架林区| 类乌齐县| 林甸县| 开封市| 台南市|