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 服务。
参考资料