如何發(fā)布和查找 WSDL 服務(wù)描述
Peter Brittenham
Web 服務(wù)架構(gòu)設(shè)計(jì)師, IBM Corporation
2001 年 11 月
在本系列的前兩個(gè)部分中,Peter 描述了如何將 WSDL 服務(wù)描述映射到 UDDI 注冊(cè)中心并且提供了特定 WSDL 用法案例。在結(jié)束語中,您將學(xué)會(huì)如何開發(fā)兩個(gè)在 UDDI 注冊(cè)中心中發(fā)布 WSDL 服務(wù)描述的 Java 應(yīng)用程序。其中,一個(gè)應(yīng)用程序?qū)⒂糜诎l(fā)布 WSDL 服務(wù)接口描述,另一個(gè)將用于發(fā)布 WSDL 服務(wù)實(shí)現(xiàn)描述。
在開始編寫用于 發(fā)布應(yīng)用程序的代碼之前,您必須理解這類應(yīng)用程序的兩個(gè)基本需求。首先, 發(fā)布應(yīng)用程序必須讀取和理解 WSDL 文檔的內(nèi)容。其次,它們必須向 UDDI 注冊(cè)中心發(fā)送請(qǐng)求,然后處理任何響應(yīng)。幸運(yùn)的是,有兩個(gè)現(xiàn)成的 Java 類庫提供這種功能,它們是:Web Services Description Language for Java(WSDL4J)和 UDDI Java API(UDDI4J)。
WSDL4J 提供可以用于解析現(xiàn)有 WSDL 文檔或通過編程創(chuàng)建新 WSDL 文檔的標(biāo)準(zhǔn) Java 接口。WSDL4J 是定位在 IBM developerWorks 網(wǎng)站上的一個(gè)開放源碼項(xiàng)目(請(qǐng)參閱 參考資料),其目的是為“Java 規(guī)范請(qǐng)求 110(Java Specification Request 110(JSR 110))”Java APIs for WSDL,提供一個(gè)參考實(shí)現(xiàn)(有關(guān)詳細(xì)信息,也請(qǐng)參閱 參考資料)。這個(gè) JSR 是通過 Java Community Process 開發(fā)的。
本文中的編程示例使用 WSDL4J V0.8。大多數(shù) WSDL4J 類表示能夠在 WSDL 文檔中出現(xiàn)的元素。例如,由 Definition 類表示 <definition>
元素,而由 Service 類表示 <service>
元素。也有使 WSDL 文檔變得易于讀取和解析以及將 WSDL4J 對(duì)象的內(nèi)容作為 XML 文檔寫出的實(shí)用類。
UDDI4J 提供一個(gè) Java 客戶機(jī)端接口,該接口可以用來在 UDDI 注冊(cè)中心中發(fā)布和查找服務(wù)描述。 這也是 IBM developerWorks 網(wǎng)站上主辦的一個(gè)開放源碼項(xiàng)目(請(qǐng)?jiān)俅螀㈤?參考資料以獲得鏈接)。
對(duì)于 發(fā)布應(yīng)用程序,我將使用 UDDI4J V1.03。這個(gè)版本提供了 UDDI V1 應(yīng)用程序編程接口的一個(gè)完整實(shí)現(xiàn)。UDDI4J 類包含 UDDI 數(shù)據(jù)實(shí)體的一個(gè)完整表示。例如,TModel 類表示 UDDI tModel
而 BusinessService 類表示 businessService
。UDDI4J 還包含一個(gè) UDDI 注冊(cè)中心代理類。這個(gè)類用于向 UDDI 注冊(cè)中心發(fā)送 publish
和 find
請(qǐng)求。
將 WSDL 服務(wù)接口作為 UDDI tModel 發(fā)布
我將通過開發(fā)一些代碼開始,這些代碼將用于發(fā)布作為 UDDI tModel 的 WSDL 服務(wù)接口描述。在本系列的第一部分,我回顧了正確發(fā)布一個(gè) WSDL 服務(wù)接口定義所需的步驟。作為開發(fā)發(fā)布應(yīng)用程序的需求,我將執(zhí)行這些步驟。這里是這些步驟的一個(gè)簡短摘要:
- 通過 WSDL 文檔的
targetNamespace
設(shè)置 tModel
名稱。
- 如果描述元素內(nèi)有一個(gè)文檔元素,那么就使用它來創(chuàng)建
tModel
描述。
- 將 WSDL 服務(wù)接口文檔的網(wǎng)絡(luò)可訪問位置放到 overviewDoc 中。
- 至少添加一個(gè)
keyedReference
,它指出該 tModel
包含對(duì) WSDL 服務(wù)描述的引用。
下面將詳細(xì)描述與每個(gè)步驟相關(guān)聯(lián)的代碼。您也可以查看和下載完整的 PublishServiceInterface 應(yīng)用程序(參請(qǐng)閱 參考資料以獲得鏈接)。
步驟 1:創(chuàng)建 tModel 并通過 targetNamespace 設(shè)置名稱
在處理這個(gè)步驟之前,您需要讀取和解析 WSDL 文檔。使用 WSDL4J 中的 WSDLReader 類來完成這個(gè)操作。在讀取 WSDL 文檔之后,創(chuàng)建一個(gè)新的 tModel
對(duì)象并通過 WSDL 文檔中的 targetNamespace
設(shè)置它的名稱。
清單 1:首先讀取和解析 WSDL 文檔
// Read WSDL service interface document
Definition def = WSDLReader.readWSDL(null, wsdlURL);
...
// Create tModel from WSDL service interface
TModel tModel = new TModel();
// [STEP 1: tModel} Set the businessService name from targetNamespace
tModel.setName(def.getTargetNamespace());
|
步驟 2:通過 WSDL 文檔元素設(shè)置 tModel 描述
設(shè)置 tModel
描述是可選的。 如果文檔元素是在定義元素內(nèi)指定的,那么它可以用于設(shè)置 tModel
描述。
清單 2:設(shè)置 tModel 描述
// Get documentation element
Element element = def.getDocumentationElement();
// [STEP 2: tModel] Set default tModel description
String desc = DOMUtils.getChildCharacterData(element);
tModel.setDefaultDescriptionString(desc);
|
步驟 3:為 tModel 創(chuàng)建 overviewDoc
overviewDoc 將包含 WSDL 服務(wù)接口文檔的網(wǎng)絡(luò)可訪問位置。在這個(gè)代碼段中,將 overviewURL 設(shè)置成 WSDL 文檔的位置。
清單 3:設(shè)置 overviewURL
// Create overview doc
OverviewDoc overviewDoc = new OverviewDoc();
// Create overview URL
OverviewURL overviewURL = new OverviewURL(wsdlURL);
// Set overviewURL
overviewDoc.setOverviewURL(overviewURL);
// [STEP 3: tModel] Set the overviewDoc
tModel.setOverviewDoc(overviewDoc);
|
步驟 4:將 tModel 歸類為 WSDL 服務(wù)描述
因?yàn)?tModel
能夠引用可以在任何標(biāo)記語言中指定的服務(wù)描述,所以指出該 tModel
表示一個(gè) WSDL 服務(wù)描述很重要。在 tModel
的 categoryBag 中添加一個(gè)附加項(xiàng)將完成這個(gè)操作。在這個(gè)樣本代碼中,有兩個(gè) keyedReference
。其中,一個(gè)指出服務(wù)描述的類型,而另一個(gè)指出實(shí)現(xiàn)這個(gè)服務(wù)接口的服務(wù)的商業(yè)用途。
清單 4:編輯 tModel 的 categoryBag
// Create a categoryBag and get the CategoryBag
categoryBag = new CategoryBag();
// Create a keyedReference for wsdlSpec
KeyedReference kr = new KeyedReference("uddi-org:types", "wsdlSpec");
kr.setTModelKey("UUID:C1ACF26D-9672-4404-9D70-39B756E62AB4");
krList.add(kr);
// Create a keyedReference for the category of service
Vector krList = new Vector();
kr = new KeyedReference("Stock market trading services", "84121801");
kr.setTModelKey("UUID:DB77450D-9FA8-45D4-A7BC-04411D14E384");
krList.add(kr);
// Set keyed reference vector
categoryBag.setKeyedReferenceVector(krList);
// [STEP 4: tModel] Set the category bag
tModel.setCategoryBag(categoryBag);
|
將 WSDL 服務(wù)實(shí)現(xiàn)作為 UDDI businessService 發(fā)布
第二個(gè)應(yīng)用程序?qū)?UDDI 中的 WSDL 服務(wù)實(shí)現(xiàn)描述作為 businessService
發(fā)布。要完成這個(gè)操作,您必須既創(chuàng)建 businessService
又創(chuàng)建 bindingTemplate
。下列步驟是基于本系列第一部分中定義的過程的。這些步驟顯示了如何既創(chuàng)建 businessService
又創(chuàng)建 bindingTemplate
,并將用作構(gòu)建您的 發(fā)布應(yīng)用程序的基礎(chǔ)。與每個(gè)步驟相關(guān)聯(lián)的代碼是從完整的 PublishServiceImplementation
應(yīng)用程序中抽取出來的。
首先我將回顧創(chuàng)建 businessService
的步驟。這里是這些步驟的摘要:
- 通過服務(wù)元素的名稱設(shè)置
businessService
名稱。
- 如果指定了名稱,使用文檔元素的內(nèi)容來創(chuàng)建
businessService
的描述。
步驟 1:創(chuàng)建 businessService 并通過服務(wù)名稱設(shè)置名稱
通過讀取和解析 WSDL 文檔的內(nèi)容開始。您使用 WSDL4J 中的 WSDLReader 類來完成這個(gè)操作。在讀取 WSDL 文檔之后,您創(chuàng)建了一個(gè)新的 businessService
對(duì)象并通過 WSDL 文檔中的服務(wù)名稱設(shè)置它的名稱。
清單 5:創(chuàng)建和命名新的 businessService 對(duì)象
// Read WSDL service implementation document Definition
wsdlDefinition = WSDLReader.readWSDL(null, wsdlURL);
// Get the first service element only
Service wsdlService =
((Service[]) wsdlDefinition.getServices().values().toArray(new Service[0]))[0];
...
// Create businessService from WSDL service interface
BusinessService businessService = new BusinessService();
...
// [STEP 1: businessService] Set the businessService name from service name
businessService.setName(wsdlService.getQName().getLocalPart());
|
步驟 2:通過 WSDL 文檔元素設(shè)置 businessService 描述
服務(wù)元素內(nèi)的 WSDL 文檔元素是用來設(shè)置 businessService
的缺省描述的:
清單 6:設(shè)置缺省 businessService 描述
// Get documentation element
element = wsdlService.getDocumentationElement();
// [STEP 2: businessService] Set default businessService description
businessService.setDefaultDescriptionString(DOMUtils.getChildCharacterData(element));
|
現(xiàn)在您已經(jīng)創(chuàng)建了一個(gè) businessService
,您可以創(chuàng)建 bindingTemplate
。這里是創(chuàng)建 bindingTemplateHere 的四個(gè)步驟的摘要:
- 如果端口元素包含文檔元素,那么使用它的內(nèi)容來創(chuàng)建
bindingTemplate
的描述。
- 使用端口元素內(nèi)的位置來設(shè)置
accessPoint
。
- 向
bindingTemplate
添加一個(gè) tModelInstanceInfo
。該元素包含 tModelKey
。
- 創(chuàng)建一個(gè)包含到 WSDL 服務(wù)實(shí)現(xiàn)文檔的引用的 overviewDoc 元素。
步驟 1:創(chuàng)建 bindingTemplate 并通過 WSDL 文檔元素設(shè)置描述
創(chuàng)建一個(gè)新的 bindingTemplate
對(duì)象,然后,通過端口元素內(nèi)的 WSDL 文檔元素設(shè)置它的缺省描述。
清單 7:創(chuàng)建和設(shè)置 bindingTemplate 對(duì)象
// Create a bindingTemplate
BindingTemplate bindingTemplate = new BindingTemplate();
// Get the first port element
Port wsdlPort = ((Port[]) wsdlService.getPorts().values().toArray(new Port[0]))[0];
// Get documentation element
element = wsdlPort.getDocumentationElement();
// [STEP 1: bindingTemplate] Set default bindingTemplate description
bindingTemplate.setDefaultDescriptionString(DOMUtils.getChildCharacterData(element));
|
步驟 2:在 bindingTemplate 內(nèi)設(shè)置訪問點(diǎn)
通過端口元素內(nèi)的可擴(kuò)展性元素設(shè)置訪問點(diǎn)。對(duì)于這個(gè)樣本代碼,我假設(shè)使用了 SOAP 綁定并且訪問點(diǎn)使用 HTTP 協(xié)議。
清單 8:設(shè)置 bindingTemplate 訪問點(diǎn)
// Get first extensibility elementExtensibility
Element ext = (ExtensibilityElement) wsdlPort.getExtensibilityElements().get(0);
// Create access point (assume that it is always SOAP binding and HTTP protocol)
AccessPoint accessPoint = new AccessPoint(((SOAPAddress)ext).getLocationURI(), "http");
// [STEP 2: bindingTemplate] Set the access point
bindingTemplate.setAccessPoint(accessPoint);
|
步驟 3:創(chuàng)建引用服務(wù)接口的 tModelInstanceInfo
bindingTemplate
必須包含一個(gè)對(duì)與服務(wù)接口定義相關(guān)聯(lián)的 tModel
的引用。通過創(chuàng)建一個(gè)包含該 tModel
的 tModelKey
的 tModelInstanceInfo
來完成這個(gè)操作。
清單 9
// [STEP 3: bindingTemplate] Create tModelInstanceInfo using the tModelKey
tModelInstanceInfo = new TModelInstanceInfo(tModelKey);
|
步驟 4:在 instanceDetails 中創(chuàng)建 overviewDoc
除了 overviewDoc 將包含 WSDL 服務(wù)實(shí)現(xiàn)文檔的位置以外,這個(gè)步驟與用于服務(wù)接口文檔的步驟類似。
清單 10
// Create overview URLOverviewURL
overviewURL = new OverviewURL(wsdlURL);
// Set overviewURL
overviewDoc.setOverviewURL(overviewURL);
// [STEP 4: bindingTemplate] Set the overview doc
instanceDetails.setOverviewDoc(overviewDoc);
|
使用發(fā)布應(yīng)用程序
您開發(fā)的 發(fā)布應(yīng)用程序可以用于發(fā)布 WSDL 服務(wù)接口和 WSDL 服務(wù)實(shí)現(xiàn)。您可以使用下述列在“參考資料”節(jié)中的 WSDL 服務(wù)描述來測試這些應(yīng)用程序:
- SQS-interface.wsdl ― 股票報(bào)價(jià)服務(wù)的 WSDL 服務(wù)實(shí)現(xiàn)描述
- SQS.wsdl ― 股票報(bào)價(jià)服務(wù)的 WSDL 服務(wù)接口描述
這些服務(wù)描述出現(xiàn)在本系列的第一篇文章中。要使用它們,必須將它們放到一個(gè)通過 Web 服務(wù)器可訪問的位置。您還必須更新 WSDL 服務(wù)實(shí)現(xiàn)文檔中導(dǎo)入元素上的位置屬性。這個(gè)屬性必須包含 WSDL 服務(wù)接口文檔的網(wǎng)絡(luò)可訪問位置。位置屬性的值的一個(gè)示例是 http://localhost:8080/wsdl/SQS-interface.wsdl。
選擇要使用的 UDDI 注冊(cè)中心
要運(yùn)行 發(fā)布應(yīng)用程序,您還需要選擇一個(gè)要使用的 UDDI 注冊(cè)中心。本節(jié)描述了不同類型的 UDDI 注冊(cè)中心,并顯示了如何使用類來訪問它們。
可以使用兩種 UDDI 注冊(cè)中心來運(yùn)行本文中的 發(fā)布應(yīng)用程序:因特網(wǎng)上可用的 UDDI 測試注冊(cè)中心或者專用 UDDI 注冊(cè)中心 ― 可以(但不是必須)在您自己的系統(tǒng)上運(yùn)行。當(dāng)運(yùn)行測試代碼時(shí),您不應(yīng)該使用公用 UDDI 注冊(cè)中心:公用 UDDI 注冊(cè)中心僅當(dāng)包含可靠數(shù)據(jù)時(shí)可能是有效的,發(fā)布測試數(shù)據(jù)到這些注冊(cè)中心將削弱其數(shù)據(jù)的可靠性。
在您選擇要使用的注冊(cè)中心之后,您應(yīng)該向 UDDI 注冊(cè)中心注冊(cè)您自己。當(dāng)您注冊(cè)時(shí),您將指定用戶標(biāo)識(shí)和密碼,您將需要使用它們來將數(shù)據(jù)發(fā)布到注冊(cè)中心。
UDDI 測試注冊(cè)中心
有兩個(gè)公用 UDDI 測試注冊(cè)中心。IBM 主管一個(gè),另一個(gè)由 Microsoft 提供。每個(gè)注冊(cè)中心有兩個(gè)接口。 inquire
接口用于在注冊(cè)中心中查找信息,而 publish
接口用于在注冊(cè)中心中發(fā)布和取消發(fā)布數(shù)據(jù)。這兩個(gè)測試注冊(cè)中心在下列位置上可訪問到:
IBM 測試注冊(cè)中心
Microsoft 測試注冊(cè)中心
專用 UDDI 注冊(cè)中心
專用 UDDI 注冊(cè)中心的一個(gè)示例是 IBM WebSphere UDDI Registry Preview(請(qǐng)參閱 參考資料以獲得鏈接)。專用 UDDI 注冊(cè)中心必須安裝在您自己系統(tǒng)之一上。在您的本地系統(tǒng)上安裝了專用注冊(cè)中心之后,使用下面一組 URL 應(yīng)該可訪問它:
創(chuàng)建 UDDI 代理
在 UDDI4J 中,UDDIProxy 類提供了到 UDDI 注冊(cè)中心的接口。每個(gè) 發(fā)布應(yīng)用程序包含一個(gè) get
方法。該方法做兩件事。首先,通過使用查詢 URL 和發(fā)布 URL 創(chuàng)建 UDDI 代理。其次,它添加使用 SSL 所需的支持(所有發(fā)布消息都通過使用一個(gè) SSL 連接發(fā)送到 UDDI 測試注冊(cè)中心。本文中的兩個(gè) 發(fā)布應(yīng)用程序都使用 IBM 的 SSL 支持,但是可以通過更改協(xié)議處理程序和安全性供應(yīng)商來使用其它實(shí)現(xiàn)。)。
清單 11:為 UDDI 注冊(cè)中心創(chuàng)建 UDDI 代理
/**
* Create the UDDI proxy for a UDDI registry.
* @param inquiryURL the inquiry URL for the UDDI registry
* @param publishURL the publish URL for the UDDI registry
* @return Returns the UDDI proxy of the IBM test registry.
*/
public static UDDIProxy get(String inquiryURL, String publishURL)
throws Exception
{
UDDIProxy uddiProxy = null;
// Add SSL support (this is IBM's SSL support
// but it can be replaced with other implementations)
System.setProperty("java.protocol.handler.pkgs",
"com.ibm.net.ssl.internal.www.protocol");
java.security.Security.addProvider(new com.ibm.jsse.JSSEProvider());
// Create UDDI proxy
uddiProxy = new UDDIProxy();
uddiProxy.setInquiryURL(inquiryURL);
uddiProxy.setPublishURL(publishURL);
// Return UDDI proxy
return uddiProxy;
}
|
運(yùn)行發(fā)布應(yīng)用程序
下表提供了每個(gè) 發(fā)布應(yīng)用程序的簡短描述及其命令行參數(shù)。
應(yīng)用程序 |
描述 |
命令行參數(shù) |
PublishServiceInterface |
讀取一個(gè) WSDL 服務(wù)接口文檔并將其作為 UDDI tModel 發(fā)布。 |
PublishServiceInterface <wsdlURL> <userid> <password> [<inquiryURL> <publishURL>] |
PublishServiceImplementation |
讀取一個(gè) WSDL 服務(wù)實(shí)現(xiàn)文檔并將其作為 UDDI businessService 發(fā)布。 |
PublishServiceImplementation <wsdlURL> <userid> <password> <businessKey> <tModelKey> [<inquiryURL> <publishURL>] |
這些命令的命令行參數(shù)是:
- wsdlURL
WSDL 文檔的網(wǎng)絡(luò)可訪問位置
- userid
在 UDDI 注冊(cè)中心上注冊(cè)的用戶標(biāo)識(shí)
- password
與用戶標(biāo)識(shí)相關(guān)聯(lián)的密碼
- businessKey
businessEntity 的 businessKey (在此發(fā)布 businessService)
- tModelKey
與 WSDL 服務(wù)接口定義相關(guān)聯(lián)的 tModel 的 tModelKey
- inquiryURL
UDDI 注冊(cè)中心的查詢 URL(缺省值是 http://www-3.ibm.com/services/uddi/testregistry/inquiryapi)
- publishURL
UDDI 注冊(cè)中心的發(fā)布 URL(缺省值是 https://www-3.ibm.com/services/uddi/testregistry/protect/publishapi)
對(duì)于 PublishServiceImplementation 應(yīng)用程序,在能夠發(fā)布 businessService
之前,必須先發(fā)布 businessEntity
。要?jiǎng)?chuàng)建 businessEntity
,您可以使用 UDDI 注冊(cè)中心的基于 Web 的用戶界面,或者使用 UDDI4J。UDDI4J:Matchmaking for Web services(請(qǐng)參閱 參考資料),包含一個(gè)如何完成該操作的示例。還有,從 PublishServiceInterface 應(yīng)用程序的輸出中可以獲得 tModelKey
命令行參數(shù)。
您可以下載這兩個(gè) 發(fā)布應(yīng)用程序并在自己的系統(tǒng)上運(yùn)行它們。要做到這一點(diǎn),您必須安裝了 WSDL4J 和 UDDI4J,連同它們所有的必備軟件。您還需要 Java Secure Socket Extension(請(qǐng)參閱“參考資料”)的一個(gè)實(shí)現(xiàn),因?yàn)樗峁?SSL 支持。
另一個(gè)選項(xiàng)是下載和安裝 IBM Web Services Toolkit(請(qǐng)參閱 參考資料)。Web Services Toolkit(WSTK)包括 WSDL4J 和 UDDI4J,以及所有其它必備軟件。如果安裝 WSTK,您可以使用 wstkenv
命令來設(shè)置編譯和運(yùn)行 發(fā)布應(yīng)用程序所需的類路徑(classpath)。 wstkenv
命令位于 WSTK 的 bin 目錄,它的用途是定義一組環(huán)境變量。這些環(huán)境變量中的一個(gè)名為 WSTK_CP;這個(gè)環(huán)境變量包含編譯和運(yùn)行 發(fā)布應(yīng)用程序所需要的類路徑。這里有一個(gè)該命令的示例,您將使用它在 Windows NT 或 Windows 2000 上運(yùn)行 PublishServiceInterface 應(yīng)用程序。
清單 12
java -cp %WSTK_CP% PublishServiceInterface <wsdlURL>
<userid> <password>
|
如果正在使用一個(gè) UDDI 測試注冊(cè)中心而您的系統(tǒng)位于防火墻后面,您將需要使用一個(gè) socks 客戶機(jī),或者指定一個(gè) socks 或代理服務(wù)器。WSTK 文檔包括 Toolkit Configuration Guide,其中包含如何完成這個(gè)操作的指示。
結(jié)束語
通過本系列文章,我描述了如何在 UDDI 注冊(cè)中心中發(fā)布和查找不同類型的 WSDL 服務(wù)描述。在這最后一篇文章中,我演示了如何使用 WSDL4J 和 UDDI4J 來發(fā)布 WSDL 服務(wù)接口和 WSDL 服務(wù)實(shí)現(xiàn)。當(dāng)在 UDDI 注冊(cè)中心中發(fā)布服務(wù)描述時(shí),遵循本系列文章中定義的過程很重要。通過遵循這個(gè)過程,您將確保潛在的服務(wù)請(qǐng)求者能夠方便地查找和使用您的 Web 服務(wù)。
參考資料
關(guān)于作者 Peter Brittenham 目前是 IBM Web Services Toolkit的首席設(shè)計(jì)師。Web Services Toolkit 包含通過使用 SOAP 和 WSDL 構(gòu)建 Web 服務(wù)時(shí)需要的工具和運(yùn)行時(shí)支持,以及對(duì) UDDI 注冊(cè)中心中發(fā)布和查找服務(wù)定義的運(yùn)行時(shí)支持。可以通過 peterbr@us.ibm.com與他聯(lián)系。 |