規(guī)格化消息路由(NMR)從JBI組件(服務(wù)引擎或綁定組件)接收消息交換并將其路由到適當(dāng)?shù)慕M件進(jìn)行處理。這種中間消息交換處理模型把服務(wù)消費者和提供者分離,并允許NMR在消息交換的生存周期中可以執(zhí)行一些附加的處理。
注意,本章中使用WSDL2.0中的術(shù)語而不是WSDL1.1。
本節(jié)介紹NMR架構(gòu)中的幾個關(guān)鍵概念。NMR的目標(biāo)是允許組件之間以服務(wù)提供者和服務(wù)消費者的身份,使用基于WSDL的服務(wù)描述彼此交互。這是組件可以進(jìn)行混合匹配(mix-and-match)裝配、構(gòu)造集成解決方案和服務(wù)基礎(chǔ)的關(guān)鍵。
WSDL [WSDL 2.0, WSDL
1.1]為JBI組件的交互提供了基本模型和描述機(jī)制。WSDL提供了一個基于XML消息交換操作的抽象服務(wù)模型,該模型可以通過擴(kuò)展提供特定的綁定信
息:將抽象模型映射到實際的通信協(xié)議和端點[WSDL 2.0 bindings] 的特定的協(xié)議信息。
JBI擴(kuò)展應(yīng)用了WSDL的抽象消息模型,可以把NMR看作是一個抽象的WSDL消息系統(tǒng)基礎(chǔ)平臺[infrastructure],綁定組件和服務(wù)引擎在這個平臺上提供和使用WSDL定義的服務(wù)。
WSDL定義了一項服務(wù)提供者和消費者之間的
消息交換操作,消息交換的參與者依照各方都能理解的一種消息交換模型進(jìn)行操作。一組相關(guān)聯(lián)的操作稱作“接口”(WSDL1.1中稱為端口類型)。一個“服
務(wù)”實現(xiàn)這樣的一個“接口”。一個服務(wù)具有一個或多個端點,每個端點通過一種特定的綁定(消息通信協(xié)議)為外部系統(tǒng)訪問該服務(wù)提供入口。
所有的這些WSDL概念都被JBI用于在APIs和SPIs中構(gòu)建服務(wù)模型。
JBI引擎和綁定組件可以作為服務(wù)消費者,服
務(wù)提供者或兩者兼具。服務(wù)提供者通過端點(endpoint)提供WSDL描述的服務(wù);服務(wù)消費者發(fā)送消息交換調(diào)用特定的操作來使用服務(wù)。服務(wù)
(service)實現(xiàn)了WSDL接口,WSDL接口是通過交換抽象定義的消息來描述的一組相關(guān)的操作。
服務(wù)消費者和服務(wù)提供者之間通常只共享抽象的服務(wù)定義而不是具體的端點信息,因而兩者之間是松耦合的。這種結(jié)構(gòu)把服務(wù)的消費者同特定的服務(wù)提供者實現(xiàn)(如特定協(xié)議)分離開來。
一個WSDL接口可以具有多個服務(wù)實現(xiàn),服務(wù)消費者在查找實現(xiàn)了某個接口的提供者時,可能會查找到多個實現(xiàn)了該接口的服務(wù)提供者(服務(wù)和相關(guān)聯(lián)的端點)。
JBI使用“規(guī)格化(normalized)”消息的概念描述服務(wù)消費者和提供者之間的交互。一條規(guī)格化消息由以下三個主要部分組成:
· 消息載荷(payload):符合抽象WSDL消息類型,不具有任何協(xié)議編碼或格式信息的XML文檔(這不是一個消息的規(guī)范格式)。
· 消息屬性(或元數(shù)據(jù)):包含了在消息處理過程中獲得的與消息相關(guān)的額外信息。消息屬性可以包含消息的安全信息(例如消息接收方的簽名信息),事務(wù)上下文信息和組件特定的信息。
規(guī)格化消息通過抽象WSDL消息類型定義為組件間的交互提供了互操作。
傳輸通道(DeliveryChannel)是綁定組件和服務(wù)引擎與NMR之間通信使用的雙向通信管道。傳輸通道構(gòu)成了服務(wù)消費者,提供者和NMR之間的交互契約,即API接口。服務(wù)消費者使用傳輸通道開始服務(wù)調(diào)用,服務(wù)提供者使用傳輸通道從NMR接收服務(wù)調(diào)用。既作為服務(wù)提供者又作為消費者的組件使用同一個傳輸通道完成這兩種功能。
以一個綁定組件接收J(rèn)BI系統(tǒng)外部的服務(wù)消費者的請求為例,當(dāng)接收這種傳入的服務(wù)調(diào)用請求后,該綁定組件通過其傳輸通道與NMR交互時必須扮演服務(wù)消費者的角色(在此用例中,綁定組件可以看作是一個服務(wù)消費者的代理)。
每個組件都具有唯一的一個傳輸通道,因此傳輸通道的實現(xiàn)必須支持在多線程環(huán)境下的并發(fā)使用。
運行時激活是服務(wù)提供者激活其提供的實際的服務(wù)的過程。在該過程中,服務(wù)提供者將其提供的服務(wù)通知NMR,這樣NMR可以將服務(wù)調(diào)用路由到該服務(wù)。端點激活分為兩步:
· 向NRM聲明一個服務(wù)端點
· 提供描述該端點定義的元數(shù)據(jù)信息
向NRM聲明一個服務(wù)端點是綁定組件或服務(wù)引擎向NMR激活一個端點名稱的過程。在NMR中聲明的端點名稱必須有相應(yīng)的元數(shù)據(jù)信息詳細(xì)描述該端點的注冊,這部分詳細(xì)信息通過使用SPI來提供。
服務(wù)調(diào)用指服務(wù)消費者和服務(wù)提供者之間的一個端對端交互的實例。盡管無法在JBI中定義一套完整的服務(wù)調(diào)用模式,但是JBI實現(xiàn)必須支持以下列表中的交互模式:
· 單向交互(One-Way)模式:服務(wù)消費者向提供者發(fā)送一個請求,服務(wù)提供者不必向消費者返回任何錯誤(故障)信息。
· 可靠的單向交互(Reliable One-Way)模式:服務(wù)消費者向提供者發(fā)送一個請求。如果服務(wù)提供者處理該請求失敗,會向消費者返回出錯信息。
· 請求-回復(fù)(Request-Response)模式:服務(wù)消費者向提供者發(fā)送一個請求,并期望服務(wù)提供者響應(yīng)。如果處理請求失敗則返回出錯信息。
· 請求-選擇回復(fù)(Request Optional-Response)模式:服務(wù)消費者向提供者發(fā)送一個請求,并期望服務(wù)提供者響應(yīng)。消費者和提供者接受到一個消息后,都可以選擇是否應(yīng)答。
上述提到的消
費者和提供者角色可能是綁定組件也可能是服務(wù)引擎。當(dāng)一個綁定組件作為服務(wù)消費者時,說明存在一個外部的服務(wù)消費者;同樣,當(dāng)一個綁定組件作為服務(wù)提供者
時,說明存在一個外部的服務(wù)提供者。當(dāng)服務(wù)引擎作為服務(wù)提供者或消費者時,說明該服務(wù)引擎是一個內(nèi)部參與者。
WSDL 2.0預(yù)定義擴(kuò)展[WSDL 2.0 Extensions]定義了一個消息交換模式(MEP)作為“一個操作中的所有抽象消息的順序和基數(shù)”。JBI使用該模式定義消費者節(jié)點和提供者節(jié)點之間的交互。該模式根據(jù)消息類型(normal或fault)和消息流向來定義。
MEPs總是以提供者的角度來理解。例如,在請求-回復(fù)交互模式中,
MEP的定義是in-out,其消息流從提供者的角度來看,請求(Request)是輸入(in),回復(fù)(Response)是輸出(out)。從服務(wù)消
費者的角度看,消息流的方向正好相反,但是NMR在與服務(wù)消費者交互過程中使用的MEP總是從服務(wù)提供者的角度來說的。當(dāng)處理WSDL
MEPs時,這是一種慣用的處理方式。In-Out模式示意圖如圖8所示:
圖8 In-Out消息交換模式
如圖所示,第
一條消息(請求)從消費者發(fā)送到提供者,從提供者的角度看其方向是輸入(in)。第二條消息(回復(fù))是從提供者到消費者,即輸出(out)。這些交換是按
給定的順序執(zhí)行的,從提供者的角度這種交換首先是輸入一條消息(in),跟著是輸出(out)一條消息,因此這種交互模式命名為輸入輸出(in-out)
模式。
消息交換
(ME)作為規(guī)格化消息的“容器(container)”。ME不僅封裝了其實現(xiàn)的消息交換模型中的輸入(in)消息和輸出(out)消息,它還包含了這
些消息的元數(shù)據(jù)信息以及正在進(jìn)行的消息交換的狀態(tài)信息。消息交換代表了JBI本地服務(wù)調(diào)用的一部分。下表說明了服務(wù)調(diào)用和消息交換模式之間的關(guān)系。
表 2 服務(wù)調(diào)用與MEP的映射
圖9兩服務(wù)引擎之間的單向服務(wù)調(diào)用
上圖描述了兩個本地服務(wù)引擎間的單向服務(wù)調(diào)用,包括了一個消息交換實例:SE1作為一個服務(wù)消費者,通過創(chuàng)建并初始化一個包含了消息請求的in-only消息交換來調(diào)用所需要的服務(wù)操作。如圖中SE1和NMR之間的對象流所示,SE1將該消息交換實例發(fā)送到NMR。
NMR決定由哪一個服務(wù)提供者提供所請求的服務(wù)操作,并把該消息交換實例傳輸給選定的提供者。在圖中表示為NMR到SE2的對象流。
注意,該圖示并不意味著調(diào)用者必須在交換完成之前阻塞當(dāng)前線程的執(zhí)行。調(diào)用方在發(fā)送和接收消息交換時,調(diào)用者可以是事件驅(qū)動的,服務(wù)引擎的內(nèi)部狀態(tài)的前進(jìn)不必占用著線程資源不放。
圖10 SE調(diào)用遠(yuǎn)程JBI實例提供的服務(wù):Robust In With Fault
下面描述圖10所示的處于兩個不同的JBI環(huán)
境中的服務(wù)引擎之間的可靠的單向調(diào)用。注意,規(guī)范中未規(guī)定如何“聯(lián)合(federating)”兩個分離的JBI實例,該例中兩個JBI實例之間通過
BC1和BC2提供的通信協(xié)議使得兩者作為遠(yuǎn)程的消費者和提供者而相互可見,并不存在影響兩者之間服務(wù)調(diào)用的特殊關(guān)系。
SE1構(gòu)建并初始化了一個可靠的單向
(robust-in)消息實例,并發(fā)送到NMR(在構(gòu)建ME實例的過程中,NMR為該實例設(shè)定了一個唯一標(biāo)識“X”)。NMR選擇合適的服務(wù)提供者,并
將消息交換以可靠的單向消息模式發(fā)送給BC1。BC1按照其所實現(xiàn)的協(xié)議需求封裝消息請求,并將該請求發(fā)送給服務(wù)提供者,在本例中,恰好是另一個通過
BC2發(fā)布了一個服務(wù)端點的JBI實例JBI2。
當(dāng)JBI2實例中的BC2組件接收到請求以后,該組件構(gòu)建一個可靠的單向消息交換實例(“Y”)并發(fā)送給NMR。JBI2中的NMR選擇合適的服務(wù)提供者并將消息交換實例(“Y”)發(fā)送給該提供者即SE2。
SE2接收實例“Y”,處理完請求之
后,SE2可能選擇返回一個故障消息說明發(fā)生了一個應(yīng)用級別的錯誤。在本例中,SE2可以使用實例“Y”返回故障消息,沿著請求流向的反向路徑最后通過消
息交換實例“X”到達(dá)JBI1中的SE1組件(在此MEP中,存在一個“done”響應(yīng)信息會沿著相同的路徑傳遞,為了清晰起見未在圖中顯示)。
圖11 SE調(diào)用遠(yuǎn)程服務(wù)
下面描述圖11所示的JBI服務(wù)引擎與JBI系統(tǒng)外部的一個遠(yuǎn)程服務(wù)提供者之間的請求-響應(yīng)調(diào)用。
服務(wù)引擎SE
創(chuàng)建并初始化一個in-out模式的消息交換實例并發(fā)送到NMR,由NMR決定哪一個服務(wù)提供者應(yīng)當(dāng)處理該調(diào)用。在本例中,BC組件被選中,BC接收到該
消息交換(in-out模式),將其反規(guī)格化(denormalize),然后通過通信協(xié)議發(fā)送到外部的服務(wù)提供者。外部提供者處理消息請求,返回適當(dāng)?shù)?
信息(正常的回復(fù)或者是應(yīng)用處理層級的錯誤消息)。BC組件規(guī)格化該回復(fù)并封裝到消息交換中,然后發(fā)送到NMR,最終返回給消費者SE。
端點,在WSDL2.0中指代一個可以通過特定協(xié)議訪問的特定的地址,用于訪問特定的服務(wù)。JBI使用這個概念表示兩種不同類型的端點:
· 外部端點(External):JBI系統(tǒng)外的端點:
· 內(nèi)部端點(Internal):JBI系統(tǒng)內(nèi)部服務(wù)提供者發(fā)布的端點,可以通過NMR的API訪問。
綁定組件在內(nèi)部端點和外部端點之間建立映射,例如,綁定組件提供的內(nèi)部端點可以映射到外部服務(wù)提供者發(fā)布的端點。
在JBI中,端點可以通過三種不同的方式進(jìn)行引用:
· 隱式引用(Implicitly):JBI根據(jù)服務(wù)類型選擇服務(wù)提供者端點
· 顯式引用(Explicitly):服務(wù)消費者根據(jù)自身的邏輯或配置選擇服務(wù)提供者端點
· 動態(tài)引用(Dynamically):在消息交換中使用一個端點引用(EPR)來提供“回調(diào)(call back)”地址供服務(wù)提供者返回應(yīng)用會話進(jìn)行過程中其它相關(guān)的消息交換信息。EPR在JBI中具有兩種不同的使用方式:
· 模式(Pattern)—每條消息交換都由一個模式描述,該模式描述了組成一個消息交換的方向(derection),順序(sequence),基數(shù)(cardinality)和消息名稱(normal或fault)。
· 起始組件(Initiator)—構(gòu)建該消息交換的組件。在所有JBI定義的消息交換模式中服務(wù)消費者組件擔(dān)當(dāng)消息交換的初始組件。
· 服務(wù)組件(Servicer)—處理該消息交換的組件。服務(wù)提供者擔(dān)當(dāng)服務(wù)組件。
· 角色(Role)—當(dāng)一個組件“擁有”某個消息交換實例時,該組件所扮演的角色,包括:
· 地址(Address)—一個服務(wù)引用,端點引用和NMR用來路由消息的邏輯地址的操作名稱。
· 消息(Message)—攜帶一條或多條消息的消息交換ME。
· 故障(Fault)—攜帶至多一條故障信息的消息交換,故障(fault)是一種特殊的消息。
· 狀態(tài)(Status)—描述消息交換的狀態(tài):error,done或active中的一種。
· 錯誤(Error)—用于描述錯誤狀態(tài)特征/原因的Java Exception對象。
· 屬性集(Properties)—消息交換的起始組件和服務(wù)組件可以為一個消息交換關(guān)聯(lián)任意的屬性信息。NMR可以保留某些屬性名稱用于聲明QoS,安全,事務(wù)或其他操作元數(shù)據(jù)。
消息交換的生命周期很短,不能夠在系統(tǒng)停止或崩潰時保留。由消費者和提供者組件提供的錯誤恢復(fù)邏輯必須能夠處理這類錯誤案例。能夠使JBI支持可恢復(fù)性的可靠的消息交換將在JBI2.0中進(jìn)行考慮。
下表是JBI使用的WSDL2.0中定義的消息交換模式。每種定義包含一個故障處理規(guī)則,指定創(chuàng)建消息交換中的哪一種消息來把故障信息從一個參與者傳到另一個參與者。與WSDL1.1等同的操作在下表中給出:
表 3 JBI標(biāo)準(zhǔn)消息交換模式(來自WSDL 2.0)
規(guī)格化消息是JBI消息交換中的消息。本節(jié)定義了規(guī)格化消息,同時討論了JBI中處理該類消息的模型。
消息的規(guī)格化指的是將協(xié)議與業(yè)務(wù)上下文信息以可傳輸?shù)姆绞酱鎯ζ饋淼倪^程。NMR處理的所有消息都是規(guī)格化的,規(guī)格化是一個雙向的過程:
· 消息的規(guī)格化(Normalizing)是
將包含了特定上下文數(shù)據(jù)的消息轉(zhuǎn)換成上下文中立的抽象表示,本質(zhì)上說就是將由NMR解釋的上下文數(shù)據(jù)轉(zhuǎn)換成一種NMR能夠理解的“通用”的表現(xiàn)形式。任何
其他的信息(如消息載荷,附加上下文等)都可以由消息承載并由NMR傳遞,但是,這些信息對NMR來說是不透明的。注意,規(guī)格化
(normalization)并不意味著要將消息載荷數(shù)據(jù)規(guī)范化(canonicalization)。
· 反規(guī)格化消息(Denormalizing)指的是從NMR接收消息并將其轉(zhuǎn)換為與上下文相關(guān)的表現(xiàn)形式。反規(guī)格化是規(guī)格化的逆向操作,例如,一個SOAP綁定組件反規(guī)格化消息時會將消息適當(dāng)?shù)牟糠忠约跋⒃獢?shù)據(jù)放入SOAP信封,轉(zhuǎn)化成需要的編碼格式。
規(guī)格化消息包含兩個不同的部分:上下文和載荷。
· 消息上下文(Message context)指的是一組消息屬性集,可為消息關(guān)聯(lián)一些元數(shù)據(jù)信息。
· 消息載荷(Message content)實際上是包含了所有消息載荷的原始數(shù)據(jù)信息的抽象。此處,術(shù)語“包含(contain)”是指包含在描述消息的抽象數(shù)據(jù)模型中。
規(guī)格化消息提
取并未規(guī)定消息載荷的處理方式。消費者可以根據(jù)特定上下文需求自由選擇消息載荷的處理方式。例如,一個高性能的綁定組件會考慮使用“拉(pull)”模式
的解析器或原始字節(jié)流來序列化消息載荷;另一方面,一個轉(zhuǎn)換引擎可能需要將整個消息載荷加載到內(nèi)存中表示成XML的DOM樹以便于查詢。
規(guī)格化消息的消息載荷一定是XML,對于非XML(包括二進(jìn)制數(shù)據(jù))的數(shù)據(jù)通過使用JAF(Java Activation Framework)將這些數(shù)據(jù)作為規(guī)格化數(shù)據(jù)的附件。
1.3.5 WSDL1.1的支持(Support for WSDL 1.1)
服務(wù)提供者可能使用WSDL1.1描述其自身而不是用WSDL2.0。由于WSDL1.1的消息模型與2.0有很大的區(qū)別,JBI定義了一個映射關(guān)系用于將WSDL1.1消息映射成為單個XML文檔的規(guī)格化消息形式。
1.4 NMR設(shè)計(NMR Design)
本節(jié)給出規(guī)格化路由的詳細(xì)設(shè)計信息。詳細(xì)講解JBI容器(綁定組件或服務(wù)引擎)和NMR之間的契約。
如前所述,激活是服務(wù)提供者向NMR聲明其所提供的服務(wù)的過程。每個聲明都必須伴有一個描述此聲明的相關(guān)元數(shù)據(jù)定義。(這些元數(shù)據(jù)由組件提供的SPI提供)JBI要求這種聲明是用WSDL1.1或WSDL2.0。NMR假設(shè)(并不強制)所有的這種聲明都符合WSDL規(guī)范。然而,如果元數(shù)據(jù)格式難看,服務(wù)的消費者就很有可能無法正確的調(diào)用該服務(wù)。
1.4.1.1 服務(wù)提供者激活(Service Provider Activation)
下圖是服務(wù)提供者激活的一個領(lǐng)域模型。
圖12 服務(wù)激活領(lǐng)域模型
每個提供者激活的端點必須使用元數(shù)據(jù)描述該服務(wù)、端點及其綁定細(xì)節(jié)。(服務(wù)引擎對其提供的服務(wù)的激活使用一種特定的JBI定義的綁定類型。)
下面用一個邏輯順序圖描述了激活的情景。
圖13 BC端點激活消息序列圖
此圖只顯示與激活相關(guān)的活動,沒有表明端點激活和消息交換之間的聯(lián)系。
1. 作為預(yù)處理,BC提供組件SPI的一個實現(xiàn),組件SPI的一部分用于提供元數(shù)據(jù)描述的激活端點。(所有的組件都必須提供這個。)
2. BC激活一個端點的名稱。
3. NMR初始化服務(wù)端點。
4. SE通過端點名稱(或其他標(biāo)準(zhǔn))查詢NMR以獲取端點。
5. SE使用端點查詢NMR獲得服務(wù)端點的元數(shù)據(jù)描述。
6. NMR調(diào)用BC的組件SPI獲取合適的元數(shù)據(jù)。
7. SE解析NMR返回的DOM文件。
本節(jié)對JBI支持的四種標(biāo)準(zhǔn)MEP進(jìn)行深入的探討。值得注意的是NMR提供了一個可擴(kuò)展的消息交流模型。JBI供應(yīng)商可以自由地擴(kuò)展四種MEP的標(biāo)準(zhǔn)目錄。
每種模式以一個狀態(tài)交換結(jié)束,用于確定交換已經(jīng)結(jié)束。這種方式對于可選消息(或默認(rèn))作為消息交換模式的一部分來說尤其有用,在所有的MEP中支持可靠消息交換。
在標(biāo)準(zhǔn)JBI模式中,以起始組件開始的交換模式一般是服務(wù)的消費者,它創(chuàng)建并初始化一個新的交換實例。服務(wù)消費者 “擁有”這個消息交換實例直到把它發(fā)送出去(使用DeliveryChannel.send())。隨后這些參與者交替接收和發(fā)送消息交換實例,直到某個參與者把消息交換狀態(tài)設(shè)置為終結(jié)狀態(tài)并把它發(fā)送給另一個參與者。當(dāng)一個組件接收一個消息交換實例(使用DeliveryChannel.accept())時,就說它“擁有”一個消息交換。
下圖顯示了對于每種標(biāo)準(zhǔn)JBI消息交換模式,服務(wù)消費者和提供者之間可能的交互。每種模式都是兩個參與者(無論它們的角色是服務(wù)提供者還是消費者)之間的契約。注意,當(dāng)接收一個消息交換實例時,一個參與者可以通過使用MessageExchange.getRole()很容易地決定它的角色是服務(wù)提供者或是消費者。這有助于參與者在參與較復(fù)雜的模式時與參與較簡單模式時一樣方便。
1.4.2.1 圖例(Diagram Key)
此處的MEP圖展示了接下來的圖例要使用到的符號。這些圖代表了消息交換的時間順序,時間在圖中顯示為從上到下。交替過程(故障或正?;貜?fù))使用選擇符號表示。
圖14 MEP圖例
1.4.2.2 In-Only消息交換模式(In-Only Message Exchange)
這種模式被用作單向消息交換。
圖15 In-Only MEP
注意:
· 服務(wù)消費者使用消息發(fā)起請求。
· 服務(wù)提供者回復(fù)狀態(tài)以完成交換。
1.4.2.3 健壯的In-Only消息交換模式(Robust In-Only Message Exchange)
這種模式被用作可靠的單向消息交換。
圖16 Robust In-Only MEP
注意:
· 服務(wù)消費者使用消息發(fā)起請求。
· 服務(wù)提供者可能回復(fù)狀態(tài)或故障。
· 如果服務(wù)提供者回復(fù)狀態(tài),那么交換完成。
· 如果服務(wù)提供者回復(fù)故障,消費者回復(fù)狀態(tài)以完成交換。
1.4.2.4 In-Out消息交換模式(In-Out Message Exchange)
這種模式被用作雙向消息交換。
圖17 In-Out MEP
注意:
· 服務(wù)消費者使用消息發(fā)起請求。
· 服務(wù)提供者回復(fù)消息或故障。
· 消費者回復(fù)狀態(tài)。
1.4.2.5 In Optional-Out消息交換模式(In Optional-Out Message Exchange)
這種模式被用作服務(wù)提供者的回復(fù)可選的雙向消息交換。
圖18 In Optional-Out MEP
注意:
· 服務(wù)消費者使用消息發(fā)起一個請求。
· 服務(wù)提供者可能回復(fù)消息、故障或狀態(tài)。
· 如果服務(wù)提供者回復(fù)狀態(tài),那么交換完成。
· 如果服務(wù)提供者回復(fù)故障,消費者必須回復(fù)狀態(tài)。
· 如果服務(wù)提供者回復(fù)消息,消費者可能回復(fù)故障或狀態(tài)。
· 如果服務(wù)消費者恢復(fù)故障,提供者必須恢復(fù)狀態(tài)以完成交換。
服務(wù)消費者使用消息交換工廠(MessageExchangeFactory)創(chuàng)建一個新的消息交換實例,并使用以下提供者可能需要的信息(這些信息為了增加特定性)初始化這個實例:接口名稱、服務(wù)名稱、端點名稱。下面給出了每種地址類型的詳細(xì)信息。如果消息交換實例中有多種地址類型,實現(xiàn)時必須使用最特定化的那個地址類型而忽略其他。
· 接口名稱。如果在一個消息交換中指定了接口名稱,實現(xiàn)必須使用隱式端點選擇。
· 服務(wù)名稱。實現(xiàn)必須選擇一個屬于給定服務(wù)名稱的服務(wù)提供者端點,使用隱式端點選擇。
· 端點。實現(xiàn)必須使用給定的端點作為服務(wù)提供者,可以使用直接或間接(直接路由和間接路由詳見5.4.3.3節(jié))
如果消息交換指定的服務(wù)可以通過不止一個端點來實現(xiàn)(當(dāng)使用接口名稱或服務(wù)名稱來查詢交換時是有可能的),必須只能選擇一個服務(wù)提供者端點。這里不再討論如何選擇端點。
當(dāng)服務(wù)提供者發(fā)出一個交換消息之后,總是先將它發(fā)送到觸發(fā)交換過程的組件。而隨后從服務(wù)的消費者返回給提供者的交換消息會被發(fā)送到一個在交換過程的初始化階段就已經(jīng)確定了的服務(wù)提供者端點。
當(dāng)一個消息交換被發(fā)送到一個指定的服務(wù)提供者端點,實現(xiàn)必須把消息交換傳輸?shù)郊せ罱o定端點的組件的傳輸通道(DeliveryChannel)。
當(dāng)一個消息交換被返回給一個服務(wù)消費者組件,實現(xiàn)必須把消息交換傳輸?shù)较M者組件的傳輸通道(DeliveryChannel)。
1.4.3.1 實現(xiàn)消息交換地址屬性的改變(Implementation Changes to Message Exchange Address Properties)
一個服務(wù)消費者可能在初始化消息交換實例的過程中選擇性地設(shè)置一些消息交換提供者的地址屬性。當(dāng)一個提供者的地址屬性被設(shè)置之后,實現(xiàn)禁止改變其他任何屬性(接口名稱、服務(wù)名稱和服務(wù)端點)。
當(dāng)組件發(fā)送一個新的交換實例,實現(xiàn)必須把交換實例的端點屬性設(shè)置為NMR選擇那個的端點(如果組件沒有指定該端點),這個端點作為服務(wù)提供者。注意,如果組件直接指定了端點,實現(xiàn)禁止改變這個端點值,即使這個端點設(shè)計到一個服務(wù)連接。(詳見5.4.3.3節(jié))
1.4.3.2 隱式端點選擇過程(Implicit Endpoint Selection Process)
當(dāng)服務(wù)消費者
使用任何形式的地址(而不是一個服務(wù)端點)指定了所需的服務(wù)提供者,JBI實現(xiàn)必須隱式地選擇服務(wù)提供者端點。本節(jié)給出實現(xiàn)進(jìn)行隱式端點選擇的過程中所必
須遵守的幾點。當(dāng)服務(wù)消費者調(diào)用DeliveryChannel.send或DeliveryChannel.sendSync發(fā)送一個消息交換實例時,
必須進(jìn)行隱式端點選擇。
如果在選擇的過程中沒有候選的服務(wù)提供者端點匹配給定的服務(wù)地址,或者沒有合適的候選服務(wù)提供者,send或者sendSync方法必須拋出一個MessagingException異常并給出相應(yīng)的出錯信息詳細(xì)描述路由故障。
JBI實現(xiàn)過程中的每個候選服務(wù)提供者端點都必須做到如下幾點:
· 調(diào)用服務(wù)消費者的Component.isExchangeWithProviderOkay()方法,提供屬于這個選擇過程的消息交換和候選選端點作為該方法的參數(shù)
· 調(diào)用服務(wù)提供者的Component.isExchangeWithConsumerOkay()方法,提供屬于這個選擇過程的消息交換和候選選端點作為該方法的參數(shù)。
一個可以使得
上述兩個調(diào)用返回為“真”的候選服務(wù)提供者端點被認(rèn)為是匹配的、適用的隱式選擇服務(wù)提供者端點。實現(xiàn)必須使用指定的方式選擇一個提供者端點,作為從所有匹
配的提供者端點中選擇的結(jié)果。一個實現(xiàn)選擇其找到的第一個匹配的服務(wù)提供者端點可能會導(dǎo)致整個選擇過程“短路”。
1.4.3.3 消息交換路由和服務(wù)連接(Message Exchange Routing and Service Connections)
服務(wù)集合可能包含提供部署信息的路由信息,稱為服務(wù)連接和服務(wù)鏈接類型。服務(wù)連接提供從消費者給出的地址到實際提供者服務(wù)端點之間的顯式映射。服務(wù)鏈接類型提供服務(wù)消費者組件希望獲得的附加信息,JBI實現(xiàn)使用服務(wù)連接路由消息交換。
服務(wù)鏈接邏輯上被定義為包含以下屬性的結(jié)構(gòu):
· 消費者地址。服務(wù)消費者提供的地址。有兩種形式:
· 提供者端點地址。實際的服務(wù)提供者的地址,將交換發(fā)送給消費者,可以是一個內(nèi)部端點或者解析過的端點引用(EPR)。
當(dāng)一個消費者使用一項特定的服務(wù)時,可能在服務(wù)單元元數(shù)據(jù)中聲明它對服務(wù)連接如何被提供的期望。此處用術(shù)語“提供者鏈接”來表示。共有三種可能的提供者鏈接類型,當(dāng)且僅當(dāng)消費者的地址是一個服務(wù)端點名稱的時候才提供:
· 標(biāo)準(zhǔn)鏈接。NMR執(zhí)行正常路由,包括使用服務(wù)連接。
· 硬鏈接。消費者一般直接指定提供者的端點,路由不受服務(wù)連接的影響。換句話說,消費者要求給定的端點地址必須是一個內(nèi)部端點。
· 軟鏈接。消費者使用一個間接地址指定提供者端點。此時消費者提供一個“假”(并不存在的)端點。這種類型的鏈接是消費者的一個聲明:給定的地址必須使用一個服務(wù)連接來解析。如果該端點是一個內(nèi)部端點的話就會引發(fā)錯誤。
服務(wù)單元在它們的部署描述符中聲明鏈接類型。JBI實現(xiàn)必須標(biāo)記消息交換,當(dāng)組件發(fā)送新的消息交換實例到傳輸通道時服務(wù)調(diào)用的鏈接類型是可用的。
如果一個新的消息交換指定了一個端點,當(dāng)調(diào)用DeliveryChannel.send時,JBI實現(xiàn)必須進(jìn)行以下幾步:
· 如果端點指定了一個內(nèi)部端點且鏈接類型是“標(biāo)準(zhǔn)鏈接”或“硬鏈接”,發(fā)送交換實例至給定的端點。
· 否則,如果端點指定了一個服務(wù)連接的消費者端點且鏈接類型是“標(biāo)準(zhǔn)鏈接”或“軟鏈接”,發(fā)送交換實例至服務(wù)連接指定的提供者端點。
· 再則,拋出一個MessagingException異常,在消息中指示錯誤類型:
注意,實現(xiàn)只能使用和當(dāng)前運行的服務(wù)集合相關(guān)聯(lián)的服務(wù)連接。
當(dāng)使用隱式端點選擇時,實現(xiàn)必須應(yīng)用服務(wù)連接選擇端點。(例如,指定一個服務(wù)類型或服務(wù)名稱而不是一個端點)。
動態(tài)端點引用(EPR)在5.1.7節(jié)給出定義。最終由綁定組件負(fù)責(zé)解析接收到的EPR,因為EPR包含了特定的綁定信息。由于同樣的原因,創(chuàng)建EPR也是綁定組件的職責(zé)。
EPR使用專門的XML詞匯,這些詞匯也是特定的綁定信息所使用的。解析收
到的EPR或創(chuàng)建一個新的EPR(服務(wù)引擎)的組件不需要“理解”EPR詞匯,但并不是禁止這樣做。在服務(wù)引擎內(nèi)部創(chuàng)建特定的EPR處理操作一般說來是不
明智的舉動,因為它在引擎和某種特定的協(xié)議之間引進(jìn)了緊耦合,降低了系統(tǒng)的可配置性。
EPR可以為內(nèi)部端點創(chuàng)建。有兩種類型的內(nèi)部端點,它們由JBI實現(xiàn)進(jìn)行不同的處理:
· 提供服務(wù)引擎的端點。這種端點的EPR必須使用JBI定義的EPR詞匯來提供引用。(見5.5.4.1)。
· 提供綁定組件的內(nèi)部端點。這種端點的EPR如果可能的話應(yīng)引用外部提供者端點,否則使用JBI定義的EPR詞匯。
EPR可以為外部端點創(chuàng)建。如上所述,一個內(nèi)部(綁定)端點作為一個外部服務(wù)的代理,如果可能的話應(yīng)該直接引用外部提供者的端點。
對被綁定組件暴露在外部的端點(為外部消費者使用),組件需要為這些外部端點創(chuàng)建EPR引用。這些外部端點可以被其他組件通過特定的查詢方式發(fā)現(xiàn)。由于這個原因,綁定組件創(chuàng)建并注冊這些外部端點。
1.4.4.1 實現(xiàn)綁定的端點(Binding-implemented Endpoints)
綁定組件需要提供對ServiceEndpoint接口的實現(xiàn),兩種EPR相關(guān)的情況:
· 外部端點。綁定組件為它創(chuàng)建的外部端點(由外部服務(wù)消費者訪問)注冊。這個外部端點作為一個代理允許外部消費者使用一個外部服務(wù)。為外部端點提供綁定的ServiceEndpoint實現(xiàn)必須做到以下幾點:
外部端點注冊的唯一目的是提供到這些端點的引用。它們不能用來處理消息交換實例。如果一個組件處理一個外部端點的消息交換實例,DeliveryChannael.send方法將拋出一個異常。
· 內(nèi)部端點。綁定組件解析一個端點引用。組件創(chuàng)建的端點解析EPR指示的服務(wù)端點。這種類型的端點可以用來處理一個消息交換實例。綁定組件的ServiceEndpoint實現(xiàn)必須做到以下幾點:
JBI實現(xiàn)必須保證,EPR解析創(chuàng)建的內(nèi)部端點處理過的消息交換,被傳輸?shù)絼?chuàng)建那個內(nèi)部端點的組件。組件實現(xiàn)必須區(qū)分JBI提供的ServiceEndpoint和組件自己創(chuàng)建的ServiceEndpoint。一個端點實現(xiàn)的例子如下所示:
classMyServiceEndpointimplementsServiceEndpoint{
privateDocumentFragmentepr_; privateQNameserviceName_; privateStringendpointName_; privateQNameinterfaceName_; MyServiceEndpoint(DocumentFragmentepr){ epr_=epr; //arealbindingcomponentwouldpickaparttheEPR,and //determineappropriateservicedescriptionitems.This //bindingjustmakesupafakedescriptionforthe //dynamicendpoint. serviceName_=newQName("http://www./services", "service1"); endpointName_="endpoint1"; interfaceName_=newQName("http://www//interfaces", "interface1"); } publicQNamegetServiceName(){ returnserviceName_; } publicStringgetEndpointName(){ returnendpointName_; } publicDocumentFragmentgetAsReference(QNameoperation){ returnepr_; } publicQName[]getInterfaces(){ returnnewQName[]{interfaceName_}; } }
NMR為服務(wù)引擎和綁定組件提供一個標(biāo)準(zhǔn)的API。
消息API定義了JBI系統(tǒng)中規(guī)格化消息的內(nèi)容和行為。該API的主要功能包括:
· 使用一個標(biāo)準(zhǔn)數(shù)據(jù)模型(XML)存儲/檢索內(nèi)容
· 在每個消息的基礎(chǔ)上set/get上下文信息(屬性)
圖19 消息API類圖
1.5.1.1 規(guī)格化消息(Normalized Message)
一個規(guī)格化的消息由以下幾部分組成:
· XML“有效載荷”文件,在抽象消息定義中定義。即規(guī)格化消息的內(nèi)容。
· 消息屬性(元數(shù)據(jù)),與消息本身相關(guān)聯(lián)。一些屬性是JBI定義的,另一些屬性可以是組件定義的。
· 消息的二進(jìn)制附件。
1.5.1.1.1 規(guī)格化消息內(nèi)容(Normalized Message Content)
規(guī)格化的消息內(nèi)容(有效載荷)是一個XML文件,在服務(wù)描述中定義(一般用XML Schema1.0)。為了提供處理XML的靈活度,規(guī)格化消息使用JAX-P API中的TraX Sourcej接口。在圖19中描述,在包javax.xml.transform中。
規(guī)格化消息內(nèi)容必須和抽象消息定義模型相一致,這個模型在服務(wù)提供者提供的服務(wù)描述中給定。
規(guī)格化消息的生產(chǎn)者必須使用NormalizedMessage.setContent()方法設(shè)置合適的XML資源以訪問有效載荷文件的內(nèi)容。規(guī)格化消息的消費者應(yīng)使用NormalizedMessage.getContent()方法,按需求消費有效載荷文件的內(nèi)容。
1.5.1.1.2 規(guī)格化消息附件(Normalized Message Attachments)
消息的附件用一個Java活動框架數(shù)據(jù)處理器(Java Activation Framework DataHandler)表示。NormalizedMessage接口包含和消息相關(guān)的增加、刪除和列表方法。一個消息可能包含任意個附件。
帶有附件的規(guī)格化消息的生產(chǎn)者負(fù)責(zé)把一個本地消息的內(nèi)容映射為帶附件的規(guī)格化消息。規(guī)格化消息的消費者負(fù)責(zé)解析消息的XML內(nèi)容并處理相關(guān)的附件。生產(chǎn)者和消費者依賴消息的WSDL定義確定規(guī)格化消息內(nèi)容的封裝結(jié)構(gòu)。
WS-I附件概述1.0(WS-I Attachments
Profile1.0(AP)) [WS-I AP]和二進(jìn)制XML優(yōu)化包(XML-binary Optimized
Packaging(XOP))[W3C
XOP]是本領(lǐng)域的兩個Web服務(wù)標(biāo)準(zhǔn)。下一小節(jié)給出在規(guī)格化消息內(nèi)容的XML體中使用這些標(biāo)準(zhǔn)引用附件的處理規(guī)則。
1.5.1.1.2.1WS-I Attachments Profile1.0的處理規(guī)則(Processing Rules for WS-I Attachments Profile 1.0)
· 在消息內(nèi)容的XML體中,每個附件都必須被一個swaRef元素/屬性引用。
· 在swaRef元素/屬性中指定的cid必須與封裝在附件內(nèi)容中的數(shù)據(jù)處理器的id相匹配。
使用帶附件的SOAP詳見[WS-I AP]
1.5.1.1.2.2W3C XML-binary Optimized Packaging (XOP)的處理規(guī)則(Processing Rules for W3C XML-binary Optimized Pachaging)
· 每個附件必須被一個XOP引用:包括消息內(nèi)容中的XML體元素。
· Href屬性值在一個XOP中指定:包括元素必須與封裝在附件內(nèi)容中的數(shù)據(jù)管理器id相匹配。
使用XOP詳見[W3C XOP]。
1.5.1.1.3 規(guī)格化消息屬性(Normalized Message Properties)
下表總結(jié)了規(guī)范定義的規(guī)格化消息的標(biāo)準(zhǔn)屬性:
表 4 標(biāo)準(zhǔn)規(guī)格化消息屬性
注
意,javax.jbi.messaging.protocol.type和
javax.jbi.messaging.protocol.headers的屬性是由綁定組件設(shè)置的。這些屬性值一般只有綁定組件自己使用,因為它們包
含特定的綁定信息。其他組件可能使用這些屬性,不過這是不明智的舉動,因為它將導(dǎo)致組件和某種特定的協(xié)議綁定。
1.5.1.1.4 WSDL 1.1定義內(nèi)容的消息(WSDL1.1-Defined Content Messages)
WSDL1.1使用術(shù)語消息部件定義抽象消息,消息部件用模型語言描述(一
般用XML
Schema)。這與WSDL2.0和JBI使用的規(guī)格化消息模型截然不同。為了允許提供用WSDL1.1定義服務(wù)的組件可以同消費者交互操作,JBI為
封裝WSDL1.1消息部件定義了一種XML文件格式。使用這種清楚的映射,可以把用來規(guī)格化內(nèi)容的消息,消費者和提供者可以交互。
一個封裝的文字化的文件須符合下面所示的模型。
defaultnamespacejbi="http://java./xml/ns/jbi/wsdl-11-wrapper"
start= elementmessage{ attributeversion{xsd:decimal}, attributetype{xsd:QName}, attributename{xsd:nmtoken}?, part* } part= elementpart{ #partvalue ((element*{text})|text) } 這個封套須在portType(抽象)操作中使用。(wsdl:input,wsdl:output,或wsdl:fault)文件中的元素<jbi:message>是這種消息所有部件的封套。它具有以下幾個屬性和元素:
· version屬性,必須是1.0。
· type屬性,包含在封套中的WSDL1.1消息定義的限定名。與wsdl:input,wsdl:output,或wsdl:fault消息屬性值相關(guān)。
· name屬性,與規(guī)格化消息的wsdl:input,wsdl:output,或wsdl:fault可選名稱屬性相關(guān)。如果這個屬性沒有提供,將應(yīng)用WSDL1.1默認(rèn)的命名規(guī)則。
· 零或多個<jbi:part>元素,表示W(wǎng)SDL1.1描述的消息的邏輯部件。消息的所有邏輯部件必須在此處顯示,與在WSDL1.1消息描述中定義的順序一致。
每個<jbi:part>元素必須包含WSDL1.1定義的消息的邏輯部分的值。<jbi:part>元素可能包含XML元素或非XML文本。
轉(zhuǎn)換成封裝的文字形式,WSDL1.1定義的消息的規(guī)格化的消息內(nèi)容也必須符合基于WSDL2.0的規(guī)格化消息內(nèi)容的要求。(例如被表示為一個javax.xml.Source)。
1.5.1.1.5 消息屬性(Message Properties)
消息屬性是與消息內(nèi)容相關(guān)的元數(shù)據(jù)。以下是本規(guī)范定義的屬性及可能用到的組件:
· 安全主題。該屬性表明JAAS主題的身份,或者為一個消息簽名,或者為一個主題簽名,由處理的上下文決定。getSecuritySubject()和setSecuritySubject()用來讀寫該規(guī)格化消息的屬性。
· 名稱/值屬性對。一個可擴(kuò)展的屬性集,組件可以為使用其它組件或其自身設(shè)置屬性。getProperty()和setProperty()用來讀寫屬性設(shè)置;getPropertyNames()可被用來發(fā)現(xiàn)所有定義的屬性名稱。
1.5.1.1.6 消息附件(Message Attachments)
消息的附件可表示為一個具名實體集,由Java活動框架處理器(Java Activation Framework handlers)處理。以下操作可被組件執(zhí)行:
· 使用唯一的名稱給規(guī)格化消息添加附件。
· 使用唯一的名稱給規(guī)格化消息移除附件。
· 列表顯示規(guī)格化消息的所有附件的名稱。
· 使用唯一的名稱從規(guī)格化消息處獲得一個附件。
附件內(nèi)容必須表示為javax.activation.DataHandler對象。
此API允許JBI組件與NMR交互。
圖20 NMR API類圖
1.5.2.1 傳輸通道(DeliveryChannel)
JBI組件和NMR通過DeliveryChannel接口進(jìn)行交互。傳輸通道使得組件可以:
· 接收和發(fā)送消息
· 創(chuàng)建消息交換工廠。
1.5.2.1.1 消息交換工廠API(Message Exchange Factory API)
所有的消息交換實例使用消息交換工廠的實例來創(chuàng)建。使用組件的傳輸通道,通過以下三種方式之一可以創(chuàng)建消息交換工廠:
· createMessageExchangeFactory(ServiceEndpoint)創(chuàng)建一個工廠,設(shè)置所有創(chuàng)建的交換實例的endpoint屬性為給定的端點。當(dāng)處理顯式選擇的端點或動態(tài)解析的端點時是很有用的。
· createMessageExchangeFactory(QName interfaceName)創(chuàng)建一個工廠,設(shè)置所有創(chuàng)建的交換實例的interfaceName屬性為給定的接口名稱。
· createMessageExchangeFactory()創(chuàng)建一個工廠,設(shè)置消息交換的所有屬性都為默認(rèn)值(null或空)。
· createMessageExchangeFactoryForService(QName serviceName)創(chuàng)建一個工廠,設(shè)置工廠創(chuàng)建的所有交換實例的service屬性為給定的服務(wù)名稱。
1.5.2.1.2 創(chuàng)建消息交換(Creating Message Exchanges)
MessageExchangeFactory提供三種不同的方法創(chuàng)建新的消息交換實例,支持三種不同的需要:
· createExchange(serviceName,operationName)根據(jù)服務(wù)名稱和操作名稱創(chuàng)建。允許組件快速裝配一個消息交換實例,不用檢查服務(wù)元數(shù)據(jù)中的MEP。
· createExchange(URI)根據(jù)MEP URI創(chuàng)建。允許支持MEP的擴(kuò)展。
· createInOnlyExchange()等。使用指定MEP的方法創(chuàng)建。在編碼時確定了MEP需求時使用此方法便于創(chuàng)建標(biāo)準(zhǔn)消息交換。
1.5.2.1.3 發(fā)送消息交換(Sending Message Exchanges)
DeliveryChannel提供兩種基本方式發(fā)送消息交換:
· Send(exchange).異步消息傳輸:此方法不會阻塞。交換可和調(diào)用那個send()的線程并發(fā)執(zhí)行。
· SendSync(exchange).同步消息傳輸;此方法必須阻塞當(dāng)前執(zhí)行的線程直到消息交換返回。
后者用一個變量存放超時參數(shù)。JBI組件可以使用簡單同步消息交換而不用在消息交換沒有按預(yù)期返回時管理“粘滯”線程。為支持超時特點,sendSync()方法返回一個布爾值來表示消息交換實例是否成功返回。如果第一個超載,sendSync(exchange)一般返回真。如果第二個超載,sendSync(exchange,long)返回假,消息交換被設(shè)置為ExchangeStatus.ERROR狀態(tài)。如果一個提供者組件試圖發(fā)送一個這樣一個消息交換(例如一個因sendSync()超時而失敗的消息交換),實現(xiàn)必須停止調(diào)用send()并拋出一個相關(guān)的MessagingException異常。
當(dāng)一個消息交換實例使用一種sendSync方法發(fā)送時,JBI實現(xiàn)設(shè)置消息交換實例的以下屬性:
Javax.jbi.messaging.sendSync.
這個屬性
注意,在異步消息交換的情況下,無法保證被接收的消息交換 (通過接收者調(diào)用accept(),下節(jié)討論)就是最初發(fā)送的同一個對象。相反,唯一的保證是消息交換的ID必須是相同的。
1.5.2.1.4 接收消息交換(Rreceiving Message Exchanges)
DeliveryChannel提供兩種方式接收消息交換:
· accept().此方法在從NMR接收到一個消息交換實例之前是阻塞的。
· accept(timeoutMS).此方法作用類似accept(),當(dāng)超過給定的時間之后,方法返回null,表明沒有接收到任何消息。
消息接收一般符合“拉”模型:JBI組件用自己的執(zhí)行線程從傳輸通道把消息交換實例“拉”出來。組件可能會使用不止一個這樣的線程做到并發(fā)消息接收。JBI實現(xiàn)可滿足一個組件以任意的順序發(fā)出的多個accept()請求。
1.5.2.1.5 關(guān)閉傳輸通道(Closing Down a DeliveryChannel)
組件可調(diào)用一個傳輸通道deactive所有的服務(wù)端點:
· close().此方法關(guān)閉所有組件激活的活動端點。
· deactivateEndpoint().調(diào)用此方法作用同上。
一旦傳輸通道這樣關(guān)閉就不能再次開放了。相反,要想使組件繼續(xù)和NMR交互,需要創(chuàng)建一個新的傳輸通道實例。
當(dāng)一個傳輸通道關(guān)閉之后,該通道創(chuàng)建的所有消息交換工廠實例都不能正常工作;所有試圖使用這樣的工廠創(chuàng)建消息交換實例都將導(dǎo)致拋出一個消息異常,表明相關(guān)的傳輸通道已經(jīng)關(guān)閉。
1.5.2.2 服務(wù)描述SPI(Service Description SPI)
使用組件接口,組件使用getServiceDescription(ServiceEndpoint)方法提供服務(wù)相關(guān)的元數(shù)據(jù)。方法返回一個DOM文件,給出某個端點提供的服務(wù)的WSDL描述。如果端點不是激活的或者端點不是由該組件提供的,getServiceDescription(ServiceEndpoint)方法返回null。
該DOM文件可以是WSDL2.0兼容的或者WSDL1.1兼容的,有以下附加屬性:
· 文件不能使用<wsdl:import>或<wsdl:include>元素。(文件必須是單獨的)。
· 服務(wù)引擎提供的端點必須使用在“JBI服務(wù)引擎WSDL綁定”一節(jié)定義的綁定類型。
文件必須提供指定服務(wù)的完整定義和端點名稱,包括服務(wù)接口和操作。(當(dāng)然也包括使用的消息交換模式)。
1.5.2.3 消息交換模式APIs(Message Exchange Pattern APIs)
下圖顯示了所有內(nèi)嵌的MEP的消息交換模式API:
圖21 MEP API類圖
所有的消息交換實例都必須由消息交換工廠(MessageExchangeFactory)的實例提供的工廠來創(chuàng)建。
消息交換實例的擁有者可以是起始組件、服務(wù)或NMR。創(chuàng)建或接收一個消息交換實例就等于把所有權(quán)授給創(chuàng)建(或接收)的那個組件。一旦對某個消息交換實例調(diào)用send()方法,組件就立即交出了它對這個消息交換實例的所有權(quán)。
sendSync()在調(diào)用該方法的過程中交出其對消息交換實例的所有權(quán)。當(dāng)調(diào)用過程結(jié)束(返回真),組件恢復(fù)對該消息實例的擁有權(quán)。
對一個消息交
換實例的擁有權(quán)意味著擁有者可以讀寫這個消息交換實例。如果一個組件(或NMR)對一個消息交換實例不具備擁有權(quán),就不能讀寫這個實例,但是可以讀取消息
交換的狀態(tài),因為狀態(tài)的訪問可以不必考慮擁有權(quán)問題。如果一個組件不是當(dāng)前消息交換實例的擁有者,而試圖對該實例調(diào)用任何方法(除了getStatus()),就會拋出一個相應(yīng)的java.lang.IllegalStateException異常。
1.5.2.3.1 消息交換(MessageExchange)
父接口MessageExchange,提供一般方法給實現(xiàn)某個特定消息交換模式的API。MessageExchange實例為一串規(guī)格化消息交換和狀態(tài)交換提供上下文環(huán)境,可被看作一個帶狀態(tài)的規(guī)格化消息的容器。
每個消息交換實例都可以通過MessageExchange API訪問以下特征:
· 狀態(tài)。ExchangeStatus在一個消息交換實例生命周期中提供其狀態(tài)的可能值。(安全類型枚舉(type-safe enumeration))。一個新消息交換實例在其生命周期內(nèi)是激活的,直到狀態(tài)轉(zhuǎn)變?yōu)?span style="color: blue;">DONE或ERROR。可分別通過getStatus()和setStatus()來獲得和設(shè)置該狀態(tài)。
· 出錯狀態(tài)源。實例可保留一個處理錯誤的根源(Java異常)。見getError()和setError()。
· 交換ID。每個MessageExchange實例必須擁有一個JBI實現(xiàn)賦予的唯一的標(biāo)識字符串。JBI組件可以用這個標(biāo)識把異步的響應(yīng)和初始的請求關(guān)聯(lián)起來。
· 交換模式。每個MessageExchange實例擁有一個交換模式標(biāo)識。標(biāo)準(zhǔn)消息交換模式由WSDL2.0賦值的URI來標(biāo)識。
· 交換角色。當(dāng)一個組件創(chuàng)建或接收某個消息交換實例,它必須認(rèn)識到自己在交換中的角色。在簡單交換模式中可以使用交換的狀態(tài)、消息和故障等特點很容易地確定組件的角色。在復(fù)雜的交換模式下,組件使用getRole()方法可以更容易地確定其在交換中的角色。
· 服務(wù)名稱。交換調(diào)用的服務(wù)的限定名。
· 操作名稱。交換調(diào)用的操作的限定名。
· 服務(wù)端點名稱。服務(wù)提供者端點可選的限定名。(服務(wù)名稱加端點名稱)。
· 規(guī)格化消息。交換實例相關(guān)的規(guī)格化消息的工廠。提供一些方法來創(chuàng)建、設(shè)置和查詢這些消息。見createMessage(),setMessage()和getMessage()。
· 故障信息。交換實例相關(guān)的故障消息的工廠。提供一些方法來創(chuàng)建、設(shè)置和查詢這些消息。見createFault(),setFault()和getFault()。
· 事務(wù)上下文。如果事務(wù)的上下文非空(non-null),執(zhí)行該交換。見getProperty()和setProperty()。事務(wù)由常量MessageExchange.JTA_TRANSACTION_PROPERTY_NAME來命名。
· 屬性。一些非JBI的消息交換特點可以作為屬性存儲:名稱-值對,值(對JBI來說)是一個不透明的java.lang.Object。
MessageExchange API提供足夠的功能支持所有標(biāo)準(zhǔn)MEP。然而,在API層次上并不區(qū)分“in”和“out”消息,使得理解Java編碼層的消息交換變得困難。為解決這個問題,提供了一套特定的MEP API,在以下四節(jié)給出詳細(xì)介紹。
1.5.2.3.2 InOnly消息交換(InOnly Message Exchange)
這個子接口為“http://www./2004/08/wsdl/in-only”MEP提供API。
提供以下特定的MEP方法:
· setInMessage(msg).只能調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。
· getInMessage()??杀欢啻握{(diào)用。如果setInMessage()方法(或setMessage(msg,“in”) )沒有被調(diào)用,返回null.
1.5.2.3.3 InOptionalOut消息交換(InOptionalOut Message Exchange)
這個子接口為“http://www./2004/08/wsdl/in-opt-out”MEP提供API。
提供以下特定的MEP方法:
· setInMessage(msg).只能由服務(wù)消費者調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。
· getInMessage().可被多次調(diào)用。如果setInMessage()方法(或setMessage(msg,“in”) )沒有被調(diào)用,返回null.
· setOutMessage(msg). 只能由服務(wù)提供調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。在此模式中設(shè)置“out”消息是可選的。
· getOutMessage().可被多次調(diào)用。如果setOutMessage()方法(或setMessage(msg,“out”) )沒有被調(diào)用,返回null.
1.5.2.3.4 InOut消息交換(InOut Message Exchange)
這個子接口為“http://www./2004/08/wsdl/in-out”MEP提供API。
提供以下特定的MEP方法:
· setInMessage(msg). 只能由服務(wù)消費者調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。
· getInMessage().可被多次調(diào)用。如果setInMessage()方法(或setMessage(msg,“in”) )沒有被調(diào)用,返回null.
· setOutMessage(msg). 只能由服務(wù)提供調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。
· getOutMessage().可被多次調(diào)用。如果setOutMessage()方法(或setMessage(msg,“out”) )沒有被調(diào)用,返回null.
1.5.2.3.5 RobustInOnly消息交換(RobustInOnly Message Exchange)
這個子接口為“http://www./2004/08/wsdl/robust-in-only”MEP提供API。
提供以下特定的MEP方法:
· setInMessage(msg). 只能由服務(wù)消費者調(diào)用一次,否則再次調(diào)用會導(dǎo)致實現(xiàn)拋出一個相應(yīng)的MessagingException異常。
· getInMessage().可被多次調(diào)用。如果setInMessage()方法(或setMessage(msg,“in”) )沒有被調(diào)用,返回null.
1.5.2.3.6 WSDL1.1消息交換屬性(WSDL1.1 Message Exchange Properties)
WSDL1.1允許對操作名稱的重載,在一個請求-響應(yīng)消息交換(in-out消息交換模式)情況下,需要哪個正確的操作不能簡單地由檢查請求消息的類型來決定。這種情況下,服務(wù)消費者應(yīng)使用以下幾個消息交換屬性說明需要哪個操作:
表5 WSDL1.1消息交換屬性
一個消費者使用上述的屬性提供所有可用的信息來解決模糊性。如果消費者無法自己解決模糊性(提供一個或多個屬性),消費者發(fā)送消息交換并允許服務(wù)提供者來解決這種模糊性。
例如,一個作為服務(wù)消費者的SOAP綁定組件,可能從一個外部服務(wù)消費者處接收到一個請求服務(wù)名稱為“foo”的操作。WSDL1.1定義的foo包括:
<definitionsxmlns="http://schemas./wsdl/"
xmlns:tns="http://www./xmlsvr" targetNamespace="http://www./xslsvr"> <types>...</types> <messagename="DoFooInput">...</message> <messagename="DoFooOutput1">...</message> <messagename="DoFooOutput2">...</message> <portTypename="FooPortType"> <operationname="Foo"> <inputname="foo-in"message="tns:DoFooInput"/> <outputname="foo-out1"message="tns:DoFooOutput1"/> </operation> <operationname="Foo"> <inputname="foo-in"message="tns:DoFooInput"/> <outputname="foo-out2"message="tns:DoFooOutput2"/> </operation> </portType> </definitions> 操作“Foo”具有模糊性。如果SOAP組件想要使用一個上述定義的內(nèi)部服務(wù),必須使用以下幾種策略的一種來解決模糊性。
· 設(shè)置InOut消息交換的"javax.jbi.messaging.wsdl-11.output-type" 屬性為以下任一種tns::DoFooOutput1 或 tns:DoFooOutput2, 分別選擇第一種或第二種Foo操作。
· 設(shè)置InOut消息交換的"javax.jbi.messaging.wsdl-11.output-name" 屬性為以下任一種:“foo-out1”或 “foo-out2”, 分別選擇第一種或第二種Foo操作。
· 設(shè)置InOut消息交換的非附加屬性。相反,消費者依賴提供者來選擇使用哪一種“Foo”操作。
綁定組件根據(jù)特定的實現(xiàn)信息選擇使用哪一種策略。(如SOAP活動headers或附加配置信息)。
服務(wù)消費者可使用組件上下文(ComponentContext)查找激活端點。(如何使用此接口詳見“框架”一章)。查找可以通過多種方式進(jìn)行,但大多數(shù)返回一個服務(wù)端點(ServiceEndpoint)對象數(shù)組。這個數(shù)組可能包含零個或多個端點;消費者必須做好準(zhǔn)備處理沒有可用的服務(wù)(零個端點)情況和多個端點訪問同一類型的服務(wù)的情況。查找方法如下:
· getEndpoint().方法返回一個特定的激活端點,該端點與提供的服務(wù)名稱或端點名稱相匹配,如果沒有匹配的則返回null.
· getEndpoints(QName interfaceName).方法返回所有實現(xiàn)給定的接口/端口類型名稱(interface/portType)的激活端點。接口名稱參數(shù)缺省時方法返回所有的激活端點。
· getEndpointsForService(QName serviceName).方法返回所有屬于給定服務(wù)名稱的激活端點。
端點(內(nèi)部或外部)在5.1.7節(jié)中定義,使用端點引用(EPR)在5.4.4節(jié)定義。本節(jié)定義了JBI中處理EPR所需的API。
EPR由組件創(chuàng)建和解析。JBI實現(xiàn)使得解析、創(chuàng)建、使用EPR的組件之間可以交互。
組件解析接收到的一個EPR時需要調(diào)用ComponentContext.resolveEndpointReference().
組件(一般是綁定組件)解析一個它理解的EPR時需要實現(xiàn)
Component.resolveEndpointReference().
提供可被EPR引用的外部端點的綁定組件使用ComponentContext.registerExternalEndpoint()方法注冊該端點,表明此外部端點是激活的。使用deregisterExternalEndpoint()表明外部端點不再是激活的,并在調(diào)用ComponentContext.getExternalEndpoints()的結(jié)果中不再顯示該端點。
用來生成EPR的組件首先選擇引用哪一個外部端點。ComponentContext提供兩種方法查找JBI系統(tǒng)中可用的外部端點:
· 使用接口名稱。getExternalEndpoints()返回一個實現(xiàn)了給定接口的所有注冊過的外部端點的數(shù)組。
· 使用服務(wù)名稱。getExternalEndpointsForService()返回一個在名稱服務(wù)中包含的所有注冊過的外部端點的數(shù)組。
例如,假定我們有一個服務(wù)引擎SE1,通過一個端點EP1提供服務(wù)。一個該服務(wù)的消費者是綁定組件BC2,發(fā)布一個外部端點EP2供EP1的外部服務(wù)消費者使用。(此時BC2作為一個外部消費者的代理)。
在一個用例中,SE1發(fā)送一個請求消息給外部服務(wù)提供者,消息中提供了指向EP2的回調(diào)地址(如,一個EP2的EPR)。目的是讓外部提供者作為一個消費者使用EPR發(fā)送請求給EP2。
在這種情景中,BC2使用JBI在創(chuàng)建時(部署時期)注冊外部端點。SE1可發(fā)現(xiàn)外部端點(使用以上的查找方法),并使用該外部端點為發(fā)送到外部提供者的請求消息創(chuàng)建一個EPR。(創(chuàng)建EPR的任務(wù)交給BC2)。外部提供者使用EPR發(fā)送所需的消息給外部端點EP2。
1.5.4.1 內(nèi)部EPR詞匯(Internal EPR Vocabulary)
服務(wù)引擎提供的內(nèi)部端點EPR,如在5.1.7中所定義的,組件可以使用XML Schema來引用EPR。這種類型的EPR僅在JBI系統(tǒng)中有用并可以用來內(nèi)部和外部提供的服務(wù)上。
defaultnamespacejbi="http://java./jbi/end-point-reference"
start= elementend-point-reference{ attributeservice-name{xsd:QName}, attributeend-point-name{text}, empty } 本節(jié)給出一般綁定組件、服務(wù)引擎和NMR交互的詳細(xì)示例。運行時激活和消息交換部分也將詳細(xì)講述。
1.5.5.1 服務(wù)消費者(Service Consumer)
這是一個單個JBI系統(tǒng)內(nèi)的例子。一個服務(wù)引擎,消費者引擎——外部Web服務(wù)的消費者(例如,對外(outbound)服務(wù)調(diào)用)。
注意:
· 服務(wù)名稱:{http:///services}:service1
· 端點名稱:soap1
· 方向:Outbound
· 操作:updateStatus(單向)
· 為簡單起見,服務(wù)引擎和綁定組件為單線程,在整個例子中只參與一個交換。
· 假定以下常量已經(jīng)聲明:
QName SERVICE1 = new QName("http:///services", "service1");
QName OP_UPDATE_STATUS = new QName("http:///services", "updateStatus");
String ENDPOINT1 = “soap1”;
1.5.5.1.1 服務(wù)引擎初始化(SE Initialization)
在一個組件的第一個“開始”之前,調(diào)用“init”方法進(jìn)行啟動前初始化。本例中,服務(wù)引擎、傳輸通道和消息交換工廠已經(jīng)準(zhǔn)備好了。
classConsumerEngineimplementsComponent,ComponentLifeCycle,
{ DeliveryChannelchannel; MessageExchangeFactoryfactory; publicvoidinit(ComponentContextcontext) throwsJBIException { //Obtainreferencetodeliverychannel channel=context.getDeliveryChannel(); //CreateourMEfactory;weuseasinglefactoryforallexchanges factory=channel.createMessageExchangeFactory(); } //... } 1.5.5.1.2 綁定組件初始化(BC Initialization)
在一個組件的第一個“開始”之前,調(diào)用“init”方法進(jìn)行啟動前初始化。本例中,同服務(wù)引擎一樣,組件創(chuàng)建好一個傳輸通道和消息交換工廠。
classConsumerEngineimplementsComponent,ComponentLifeCycle,
{ DeliveryChannelchannel; MessageExchangeFactoryfactory; publicvoidinit(ComponentContextcontext) throwsJBIException { //Obtainreferencetodeliverychannel channel=context.getDeliveryChannel(); //CreateourMEfactory;weuseasinglefactoryforallexchanges factory=channel.createMessageExchangeFactory(); } //... }
classSoapBindingimplementsComponent,ComponentLifeCycle{
DeliveryChannelchannel; ServiceEndpointserviceEndpoint; publicvoidinit(ComponentContextcontext) throwsJBIException{ //Obtainreferencetodeliverychannel channel=context.getDeliveryChannel(); //Activateendpointnames serviceEndpoint=context.activateEndpoint(SERVICE1,ENDPOINT1); } publicDocumentgetServiceDescription(ServiceEndpointref){ Documentresult=null; //returnWSDLdescribingservicesofferedbymethroughthegiven //servicereference. if(ref.getServiceName.equals(SERVICE1)&& ref.getEndpointName.equals(ENDPOINT1)){ //...createorfindtheWSDL } returnresult; } //... } 1.5.5.1.3 消息交換(Message Exchange)
從服務(wù)引擎的角度
voidsomeEngineMethod()
{ InOnlyinOnly; Messagemessage; //Asinitator,wegettocreatethemessageexchange inOnly=factory.createInOnlyExchange(); //Createnewmessageforthisexhange. message=inOnly.createMessage(); //Populatemessagewithdata(omitted) //Setmessageasinreferenceinexchange inOnly.setInMessage(message); //Setoperationandservicedetails //(Wecouldavoidthisbyusingchannel.createExchange(SERVICE1, //OP_UPDATE_STATUS);above) inOnly.setOperation(OP_UPDATE_STATUS); inOnly.setService(SERVICE1); //WewillallowtheNMRtoselecttheendpointautomatically. //Alternatively,wecouldquerytheavailableendpointsimplementingSERVICE1, //choosefromthatlist,anduseinOnly.setEndpoint()toroutetheMEourselves. //Initiatethemessageexchange channel.send(inOnly); } 從綁定組件的角度
voidsomeBindingMethod()
{ MessageExchangeexchange=channel.accept(); if(exchangeinstanceofInOnly) process((InOnly)exchange); else//... } voidprocess(InOnlyinOnly) { NormalizedMessageinMsg; //fetch"in"messagefromexchange inMsg=inOnly.getInMessage(); //processdata try { //commitmessagetowire(omitted) //setstatusappropriately inOnly.setStatus(ExchangeStatus.DONE); } catch(Exceptionex) { //ImplicitlysetsinOnlystatustoExchangeStatus.ERROR inOnly.setError(ex); } channel.send(inOnly); } 1.5.5.2 服務(wù)提供者(服務(wù)者)(Service Provider[Servicer])
這是一個單個JBI系統(tǒng)內(nèi)的例子。一個服務(wù)引擎,提供者引擎——通過一個SOAP綁定組件提供一個面向外部消費者的服務(wù)(例如,對內(nèi)(inbound)服務(wù)調(diào)用)。
注意:
· 服務(wù)名稱:{http:///services}:service2
· 端點名稱:engine2
· 方向:Inbound
· 操作:getStockQuote(請求-響應(yīng))
· 為簡單起見,服務(wù)引擎和綁定組件為單線程,在整個例子中只參與一個交換。
· 假定以下常量已經(jīng)聲明:
QName SERVICE2 = new QName("http:///services", "service2");
String ENDPOINT2 = “engine2”;
1.5.5.2.1 綁定組件初始化(BC Initialization)
classSoapBindingimplementsComponent,ComponentLifeCycle{
DeliveryChannelchannel; MessageExchangeFactoryfactory; publicvoidinit(ComponentContextcontext) throwsJBIException{ //Obtainreferencetodeliverychannel channel=context.getDeliveryChannel(); //CreatesingleMEfactory;wewilluseitforcreatingallexchangesneeded factory=channel.createMessageExchangeFactory(); //CreatelistenerforinboundSOAPmessages //(omitted) } } 1.5.5.2.2 服務(wù)引擎初始化(SE Initialization)
classProviderEngineimplementsComponent,ComponentLifeCycle{
DeliveryChannelchannel; ServiceEndpointserviceEndpoint; publicvoidinit(ComponentContextcontext) throwsJBIException { //Obtainreferencetodeliverychannel channel=context.getDeliveryChannel(); //Activateserviceendpoint(SEVICE2,ENDPOINT2) serviceEndpoint=context.activateEndpoint(SERVICE2,ENDPOINT2); } publicDocumentgetServiceDescription(ServiceEndpointref){ Documentresult=null; //returnWSDLdescribingservicesofferedbymethroughthegiven //servicereference. if(ref.getServiceName.equals(SERVICE2)&& ref.getEndpointName.equals(ENDPOINT2)){ //...createorfindtheWSDL } returnresult; } //... } 1.5.5.2.3 消息傳輸(Message Delivery)
從綁定組件角度
voidsomeBindingMethod(){
InOutinOut; NormalizedMessageinMsg; //Receivemessageovernativeprotocol(omitted) //CreateInOutexchange inOut=factory.createInOutExchange(); //Createnewmessage inMsg=inOut.createMessage(); //Normalizenativeprotocoldata(omitted) //Setmessageasinreferenceinexchange inOut.setInMessage(inMsg); //Setoperationandservicedetails inOut.setOperation(newQName(SERVICE2.getNamespaceURI(),"getStockQuote")); inOut.setService(SERVICE2); //Initiatethemessageexchangeandwaitforresponse channel.sendSync(inOut); process((InOut)inOut); } voidprocess(InOutinOut){ NormalizedMessageoutMsg=inOut.getOutMessage(); if(inOut.getStatus()!=ExchangeStatus.ACTIVE){ //erroroccurred.Returnerrorresponseinnativewireprotocol(omitted) }else{ //commitresponsemessagetonativewireprotocol(omitted) //Tellproviderthattheexchangeisnowcomplete. inOut.setStatus(ExchangeStatus.DONE); channel.send(inOut); } } 從服務(wù)引擎角度
voidsomeEngineMethod(){
MessageExchangeexchange=channel.accept(); if(exchangeinstanaceofInOut) process((InOut)exchange); else//... } voidprocess(InOutinOut){ NormalizedMessageinMsg; NormalizedMessageoutMsg; //fetchinmessage inMsg=inOut.getInMessage(); //processdata try{ //performappropriateprocessingtoinMsg(omitted) //createresponsemessage outMsg=inOut.createMessage(); //populatemessagecontent(omitted); //attachmessagetoexchange inOut.setOutMessage(outMsg); } catch(Exceptionex){ //ImplicitlysetsinOutstatustoExchangeStatus.ERROR inOut.setError(ex); } channel.send(inOut); } 1.5.5.3 解析動態(tài)端點引用(Resolution of Dynamic Endpoint Reference)
下表顯示了一個服務(wù)消費者的解析EPR的例子。
MessageExchangecreateExchangeForEPR(DocumentFragmentepr,QNameoperationName)
throwsMessagingException,Exception { MessageExchangeresult; ServiceEndpointendpoint=context_.resolveEndpointReference(epr); if(endpoint!=null){ result=channel_.createExchangeFactory(endpoint). createExchange(endpoint.getServiceName(),operationName); } else{ thrownewException("CannotresolveEPR"); } returnresult; } 1.5.5.4 創(chuàng)建動態(tài)端點引用(Creation of a Dynamic Endpoint Reference)
下表顯示了一個服務(wù)提供者創(chuàng)建EPR的例子。
privateDocumentFragmentgetEpr(QNameinterfaceName,QNameoperationName){
DocumentFragmentresult=null; ServiceEndpoint[]endpoints=context_.getExternalEndpoints(interfaceName); if(endpoints.length>0){ ServiceEndpointendpoint=endpoints[0];//simplechoice result=endpoint.getAsReference(operationName); } returnresult; } 每個服務(wù)提供者必須實現(xiàn)ComponentgetServiceDescription()方法。當(dāng)NMR要檢索組件提供的服務(wù)的元數(shù)據(jù)時調(diào)用該方法,服務(wù)必須已被NMR激活。(使用名稱)
JBI通過特定的綁定類型對標(biāo)準(zhǔn)WSDL1.1和WSDL2.0作了補充,服務(wù)引擎使用特定的JBI綁定類型其提供的服務(wù)聲明端點。綁定類型將在下一小節(jié)定義。
1.5.6.1 JBI服務(wù)引擎WSDL綁定(JBI Service Engine WSDL Binding)
JBI1.0服務(wù)引擎綁定通過給WSDL綁定組件的type屬性賦以下值來標(biāo)識:
“http://java./xml/ns/jbi/binding/service+engine”。
這種綁定類型用來標(biāo)識服務(wù)引擎(如,JBI系統(tǒng)中的本地服務(wù)提供者)。它不能定義WSDL操作或消息的映射。使用所有的抽象WSDL定義時都無需修改。
|
|