http://www.microsoft.com/China/msdn/Archives/msdnonline/features/articles/wsdl.asp
如何發布和查找 WSDL 服務描述
Peter Brittenham
Web 服務架構設計師, IBM Corporation
2001 年 11 月
在本系列的前兩個部分中,Peter 描述了如何將 WSDL 服務描述映射到 UDDI 注冊中心并且提供了特定 WSDL 用法案例。在結束語中,您將學會如何開發兩個在 UDDI 注冊中心中發布 WSDL 服務描述的 Java 應用程序。其中,一個應用程序將用于發布 WSDL 服務接口描述,另一個將用于發布 WSDL 服務實現描述。
在開始編寫用于 發布應用程序的代碼之前,您必須理解這類應用程序的兩個基本需求。首先, 發布應用程序必須讀取和理解 WSDL 文檔的內容。其次,它們必須向 UDDI 注冊中心發送請求,然后處理任何響應。幸運的是,有兩個現成的 Java 類庫提供這種功能,它們是:Web Services Description Language for Java(WSDL4J)和 UDDI Java API(UDDI4J)。
WSDL4J 提供可以用于解析現有 WSDL 文檔或通過編程創建新 WSDL 文檔的標準 Java 接口。WSDL4J 是定位在 IBM developerWorks 網站上的一個開放源碼項目(請參閱 參考資料),其目的是為“Java 規范請求 110(Java Specification Request 110(JSR 110))”Java APIs for WSDL,提供一個參考實現(有關詳細信息,也請參閱 參考資料)。這個 JSR 是通過 Java Community Process 開發的。
本文中的編程示例使用 WSDL4J V0.8。大多數 WSDL4J 類表示能夠在 WSDL 文檔中出現的元素。例如,由 Definition 類表示 <definition>
元素,而由 Service 類表示 <service>
元素。也有使 WSDL 文檔變得易于讀取和解析以及將 WSDL4J 對象的內容作為 XML 文檔寫出的實用類。
UDDI4J 提供一個 Java 客戶機端接口,該接口可以用來在 UDDI 注冊中心中發布和查找服務描述。 這也是 IBM developerWorks 網站上主辦的一個開放源碼項目(請再次參閱 參考資料以獲得鏈接)。
對于 發布應用程序,我將使用 UDDI4J V1.03。這個版本提供了 UDDI V1 應用程序編程接口的一個完整實現。UDDI4J 類包含 UDDI 數據實體的一個完整表示。例如,TModel 類表示 UDDI tModel
而 BusinessService 類表示 businessService
。UDDI4J 還包含一個 UDDI 注冊中心代理類。這個類用于向 UDDI 注冊中心發送 publish
和 find
請求。
將 WSDL 服務接口作為 UDDI tModel 發布
我將通過開發一些代碼開始,這些代碼將用于發布作為 UDDI tModel 的 WSDL 服務接口描述。在本系列的第一部分,我回顧了正確發布一個 WSDL 服務接口定義所需的步驟。作為開發發布應用程序的需求,我將執行這些步驟。這里是這些步驟的一個簡短摘要:
- 通過 WSDL 文檔的
targetNamespace
設置 tModel
名稱。
- 如果描述元素內有一個文檔元素,那么就使用它來創建
tModel
描述。
- 將 WSDL 服務接口文檔的網絡可訪問位置放到 overviewDoc 中。
- 至少添加一個
keyedReference
,它指出該 tModel
包含對 WSDL 服務描述的引用。
下面將詳細描述與每個步驟相關聯的代碼。您也可以查看和下載完整的 PublishServiceInterface 應用程序(參請閱 參考資料以獲得鏈接)。
步驟 1:創建 tModel 并通過 targetNamespace 設置名稱
在處理這個步驟之前,您需要讀取和解析 WSDL 文檔。使用 WSDL4J 中的 WSDLReader 類來完成這個操作。在讀取 WSDL 文檔之后,創建一個新的 tModel
對象并通過 WSDL 文檔中的 targetNamespace
設置它的名稱。
清單 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 文檔元素設置 tModel 描述
設置 tModel
描述是可選的。 如果文檔元素是在定義元素內指定的,那么它可以用于設置 tModel
描述。
清單 2:設置 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 創建 overviewDoc
overviewDoc 將包含 WSDL 服務接口文檔的網絡可訪問位置。在這個代碼段中,將 overviewURL 設置成 WSDL 文檔的位置。
清單 3:設置 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 服務描述
因為 tModel
能夠引用可以在任何標記語言中指定的服務描述,所以指出該 tModel
表示一個 WSDL 服務描述很重要。在 tModel
的 categoryBag 中添加一個附加項將完成這個操作。在這個樣本代碼中,有兩個 keyedReference
。其中,一個指出服務描述的類型,而另一個指出實現這個服務接口的服務的商業用途。
清單 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 服務實現作為 UDDI businessService 發布
第二個應用程序將 UDDI 中的 WSDL 服務實現描述作為 businessService
發布。要完成這個操作,您必須既創建 businessService
又創建 bindingTemplate
。下列步驟是基于本系列第一部分中定義的過程的。這些步驟顯示了如何既創建 businessService
又創建 bindingTemplate
,并將用作構建您的 發布應用程序的基礎。與每個步驟相關聯的代碼是從完整的 PublishServiceImplementation
應用程序中抽取出來的。
首先我將回顧創建 businessService
的步驟。這里是這些步驟的摘要:
- 通過服務元素的名稱設置
businessService
名稱。
- 如果指定了名稱,使用文檔元素的內容來創建
businessService
的描述。
步驟 1:創建 businessService 并通過服務名稱設置名稱
通過讀取和解析 WSDL 文檔的內容開始。您使用 WSDL4J 中的 WSDLReader 類來完成這個操作。在讀取 WSDL 文檔之后,您創建了一個新的 businessService
對象并通過 WSDL 文檔中的服務名稱設置它的名稱。
清單 5:創建和命名新的 businessService 對象
// 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 文檔元素設置 businessService 描述
服務元素內的 WSDL 文檔元素是用來設置 businessService
的缺省描述的:
清單 6:設置缺省 businessService 描述
// Get documentation element
element = wsdlService.getDocumentationElement();
// [STEP 2: businessService] Set default businessService description
businessService.setDefaultDescriptionString(DOMUtils.getChildCharacterData(element));
|
現在您已經創建了一個 businessService
,您可以創建 bindingTemplate
。這里是創建 bindingTemplateHere 的四個步驟的摘要:
- 如果端口元素包含文檔元素,那么使用它的內容來創建
bindingTemplate
的描述。
- 使用端口元素內的位置來設置
accessPoint
。
- 向
bindingTemplate
添加一個 tModelInstanceInfo
。該元素包含 tModelKey
。
- 創建一個包含到 WSDL 服務實現文檔的引用的 overviewDoc 元素。
步驟 1:創建 bindingTemplate 并通過 WSDL 文檔元素設置描述
創建一個新的 bindingTemplate
對象,然后,通過端口元素內的 WSDL 文檔元素設置它的缺省描述。
清單 7:創建和設置 bindingTemplate 對象
// 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 內設置訪問點
通過端口元素內的可擴展性元素設置訪問點。對于這個樣本代碼,我假設使用了 SOAP 綁定并且訪問點使用 HTTP 協議。
清單 8:設置 bindingTemplate 訪問點
// 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:創建引用服務接口的 tModelInstanceInfo
bindingTemplate
必須包含一個對與服務接口定義相關聯的 tModel
的引用。通過創建一個包含該 tModel
的 tModelKey
的 tModelInstanceInfo
來完成這個操作。
清單 9
// [STEP 3: bindingTemplate] Create tModelInstanceInfo using the tModelKey
tModelInstanceInfo = new TModelInstanceInfo(tModelKey);
|
步驟 4:在 instanceDetails 中創建 overviewDoc
除了 overviewDoc 將包含 WSDL 服務實現文檔的位置以外,這個步驟與用于服務接口文檔的步驟類似。
清單 10
// Create overview URLOverviewURL
overviewURL = new OverviewURL(wsdlURL);
// Set overviewURL
overviewDoc.setOverviewURL(overviewURL);
// [STEP 4: bindingTemplate] Set the overview doc
instanceDetails.setOverviewDoc(overviewDoc);
|
使用發布應用程序
您開發的 發布應用程序可以用于發布 WSDL 服務接口和 WSDL 服務實現。您可以使用下述列在“參考資料”節中的 WSDL 服務描述來測試這些應用程序:
- SQS-interface.wsdl ― 股票報價服務的 WSDL 服務實現描述
- SQS.wsdl ― 股票報價服務的 WSDL 服務接口描述
這些服務描述出現在本系列的第一篇文章中。要使用它們,必須將它們放到一個通過 Web 服務器可訪問的位置。您還必須更新 WSDL 服務實現文檔中導入元素上的位置屬性。這個屬性必須包含 WSDL 服務接口文檔的網絡可訪問位置。位置屬性的值的一個示例是 http://localhost:8080/wsdl/SQS-interface.wsdl。
選擇要使用的 UDDI 注冊中心
要運行 發布應用程序,您還需要選擇一個要使用的 UDDI 注冊中心。本節描述了不同類型的 UDDI 注冊中心,并顯示了如何使用類來訪問它們。
可以使用兩種 UDDI 注冊中心來運行本文中的 發布應用程序:因特網上可用的 UDDI 測試注冊中心或者專用 UDDI 注冊中心 ― 可以(但不是必須)在您自己的系統上運行。當運行測試代碼時,您不應該使用公用 UDDI 注冊中心:公用 UDDI 注冊中心僅當包含可靠數據時可能是有效的,發布測試數據到這些注冊中心將削弱其數據的可靠性。
在您選擇要使用的注冊中心之后,您應該向 UDDI 注冊中心注冊您自己。當您注冊時,您將指定用戶標識和密碼,您將需要使用它們來將數據發布到注冊中心。
UDDI 測試注冊中心
有兩個公用 UDDI 測試注冊中心。IBM 主管一個,另一個由 Microsoft 提供。每個注冊中心有兩個接口。 inquire
接口用于在注冊中心中查找信息,而 publish
接口用于在注冊中心中發布和取消發布數據。這兩個測試注冊中心在下列位置上可訪問到:
IBM 測試注冊中心
Microsoft 測試注冊中心
專用 UDDI 注冊中心
專用 UDDI 注冊中心的一個示例是 IBM WebSphere UDDI Registry Preview(請參閱 參考資料以獲得鏈接)。專用 UDDI 注冊中心必須安裝在您自己系統之一上。在您的本地系統上安裝了專用注冊中心之后,使用下面一組 URL 應該可訪問它:
創建 UDDI 代理
在 UDDI4J 中,UDDIProxy 類提供了到 UDDI 注冊中心的接口。每個 發布應用程序包含一個 get
方法。該方法做兩件事。首先,通過使用查詢 URL 和發布 URL 創建 UDDI 代理。其次,它添加使用 SSL 所需的支持(所有發布消息都通過使用一個 SSL 連接發送到 UDDI 測試注冊中心。本文中的兩個 發布應用程序都使用 IBM 的 SSL 支持,但是可以通過更改協議處理程序和安全性供應商來使用其它實現。)。
清單 11:為 UDDI 注冊中心創建 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;
}
|
運行發布應用程序
下表提供了每個 發布應用程序的簡短描述及其命令行參數。
應用程序 |
描述 |
命令行參數 |
PublishServiceInterface |
讀取一個 WSDL 服務接口文檔并將其作為 UDDI tModel 發布。 |
PublishServiceInterface <wsdlURL> <userid> <password> [<inquiryURL> <publishURL>] |
PublishServiceImplementation |
讀取一個 WSDL 服務實現文檔并將其作為 UDDI businessService 發布。 |
PublishServiceImplementation <wsdlURL> <userid> <password> <businessKey> <tModelKey> [<inquiryURL> <publishURL>] |
這些命令的命令行參數是:
- wsdlURL
WSDL 文檔的網絡可訪問位置
- userid
在 UDDI 注冊中心上注冊的用戶標識
- password
與用戶標識相關聯的密碼
- businessKey
businessEntity 的 businessKey (在此發布 businessService)
- tModelKey
與 WSDL 服務接口定義相關聯的 tModel 的 tModelKey
- inquiryURL
UDDI 注冊中心的查詢 URL(缺省值是 http://www-3.ibm.com/services/uddi/testregistry/inquiryapi)
- publishURL
UDDI 注冊中心的發布 URL(缺省值是 https://www-3.ibm.com/services/uddi/testregistry/protect/publishapi)
對于 PublishServiceImplementation 應用程序,在能夠發布 businessService
之前,必須先發布 businessEntity
。要創建 businessEntity
,您可以使用 UDDI 注冊中心的基于 Web 的用戶界面,或者使用 UDDI4J。UDDI4J:Matchmaking for Web services(請參閱 參考資料),包含一個如何完成該操作的示例。還有,從 PublishServiceInterface 應用程序的輸出中可以獲得 tModelKey
命令行參數。
您可以下載這兩個 發布應用程序并在自己的系統上運行它們。要做到這一點,您必須安裝了 WSDL4J 和 UDDI4J,連同它們所有的必備軟件。您還需要 Java Secure Socket Extension(請參閱“參考資料”)的一個實現,因為它提供 SSL 支持。
另一個選項是下載和安裝 IBM Web Services Toolkit(請參閱 參考資料)。Web Services Toolkit(WSTK)包括 WSDL4J 和 UDDI4J,以及所有其它必備軟件。如果安裝 WSTK,您可以使用 wstkenv
命令來設置編譯和運行 發布應用程序所需的類路徑(classpath)。 wstkenv
命令位于 WSTK 的 bin 目錄,它的用途是定義一組環境變量。這些環境變量中的一個名為 WSTK_CP;這個環境變量包含編譯和運行 發布應用程序所需要的類路徑。這里有一個該命令的示例,您將使用它在 Windows NT 或 Windows 2000 上運行 PublishServiceInterface 應用程序。
清單 12
java -cp %WSTK_CP% PublishServiceInterface <wsdlURL>
<userid> <password>
|
如果正在使用一個 UDDI 測試注冊中心而您的系統位于防火墻后面,您將需要使用一個 socks 客戶機,或者指定一個 socks 或代理服務器。WSTK 文檔包括 Toolkit Configuration Guide,其中包含如何完成這個操作的指示。
結束語
通過本系列文章,我描述了如何在 UDDI 注冊中心中發布和查找不同類型的 WSDL 服務描述。在這最后一篇文章中,我演示了如何使用 WSDL4J 和 UDDI4J 來發布 WSDL 服務接口和 WSDL 服務實現。當在 UDDI 注冊中心中發布服務描述時,遵循本系列文章中定義的過程很重要。通過遵循這個過程,您將確保潛在的服務請求者能夠方便地查找和使用您的 Web 服務。
參考資料