- 浏览: 48300 次
- 性别:
- 来自: 杭州
文章分类
最新评论
(本文最初由IBMdeveloperWorks中国网站发表,其网址是http://www.ibm.com/developerWorks/cn/)
本文是架构Web服务的系列文章的第六篇,也是最后一篇,文本以前文为基础,在前文的应用实例的基础上,考察了发布Web服务界面的整个过程:XMLSchema建模、WSDL发布和UDDI注册。通过本文,大家可以详细具体地了解各个XML和WebService的系列规范在WebService的发布时所起的左右,对WebService技术也将有一个深入的理解。
在前文中,我已经介绍过,Web服务是通过SOAP消息调用的,通过WSDL进行界面描述的,以及通过UDDI进行公共注册发布的。在前一篇文章中,我已经介绍了如何进行SOAPAPI的消息定义,那么在本文中,我将单把save_category提出来,看看在具体的实现上,应当如何对这个消息使用W3CXMLSchema进行建模,如果使用WSDL将基于该消息调用的Web服务进行规范描述并交付调用者,以及如何将这个Web服务连同它的WSDL规范化描述文件一起发布到UDDI注册中心中去。希望大家能通过本文的实例讲解,在本系列的最后完整地了解Web服务的工作原理和相关技术规范的作用。
本文所引用的资源主要包括两类,一类是Web服务的技术资源网站,包含了大量Web服务的技术信息,另一类是Web服务“stack"系列技术规范,他们是一个整体的技术体系,包括UDDI、SOAP、WSDL、XMLSchema,XML等。本文的最后给出了这些资源的链接,有兴趣的读者可以通过这些资源链接找到所需的内容。
SOAP消息示例
以下是一个save_category的调用例子,在例子中使用了SOAPHTTPBinding(使用的SOAP规范的版本是1.2),假设目标Web服务被部署在www.sagitta.com,而调用的Web服务的入口位置将是http://www.sagitta.com/catalog/。
在这个消息中,将在一个现有的category中添加一个新的category和一个新的product。
POST /catalog HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://www.sagitta.com/catalog/"
Host: www.sagitta.com
<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Body>
<save_category xmlns="http://www.sagitta.com/schema/">
<authInfo>5Az784kJceHCE982eB</authInfo>
<category categoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073"
parentCategoryKey="ab4e3de1-7865-f2c1-b49a-beccbd21c072">
<name>Consumer Electronics</name>
<description>Product Category for Consumer Electronics </description>
<category categoryKey="" parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073">
<name>SONY Consumer Electronics</name>
<description>Sony's Product Category for Consumer Electronics</description>
</category>
<product productKey="" parentCategoryKey=" cb4e17d1-6100-47f6-a532-cd9cbd30c073">
<name>DSC-S75 Digital Camera</name>
<description>Sony's Brand-New Professional Digital Camera</description>
<compliantSpecBag>
<specification specificationKey="Key[USB1.1]" />
</compliantSpecBag>
<featureBag>
<feature>……</feature>
<feature>……</feature>
</featureBag>
<parameterBag>
……
</parameterBag>
</product>
</category>
</save_category>
</env:Body>
</env:Envelope>
该调用消息的返回消息可能是:
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Body>
<categoryList xmlns="http://www.sagitta.com/schema/">
<category categoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073"
parentCategoryKey="ab4e3de1-7865-f2c1-b49a-beccbd21c072">
<category categoryKey="8933aa50-3aaf-11d5-80dc-002035229c64"
parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073" />
<product productKey="89307600-3aaf-11d5-80dc-002035229c64"
parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073" />
</category>
</categoryList>
</env:Body>
</env:Envelope>
从中我们可以看到在save_category和categoryList两个元素后面都带了一个xmlns的修饰"http://www.sagitta.com/schema/"。这URI唯一表示了该元素及其所有子元素的的命名空间。同时通过这个URL可以获得这些元素的Schema定义。
使用W3CXMLSchema描述的XML文档的模式定义在整个Web服务的技术系列中处于一个支持工具的地位。W3CXMLSchema是任何类型的XML文档的建模工具。在Web服务体系中,无论在SOAP消息的表示上,还是在WSDL的界面描述上,XMLSchema都是不可缺少的重要工具和底层支持。
下面我将从XMLSchema开始,针对save_category这个消息(同时也对应一个服务入口)逐一介绍如何为我们的XML消息进行XMLSchema建模,如何使用WSDL将save_category这个服务入口进行界面描述,然后将这个入口发布到UDDI注册中心中去。
XMLSchema建模
XMLSchema的文件后缀是.xsd文件,一个XMLSchema中的定义通常分为两部分,型(Type)定义和元素(Element)定义。下面我们结合save_category具体的XMLSchema定义来说明如何使用XMLSchema来实现模式定义。
在下面的XMLSchema文档中,型定义包括:compliantSpecBag,featureBag,parameter,parameterBag,product和category六个类型,而元素定义为save_category这一个元素。
save_category的XMLSchema描述定义:(完整的XMLSchema文档是:sagitta.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
以上是XMLSchema的文件头。
<xs:complexType name="compliantSpecBag">
<xs:sequence>
<xs:element name="specification" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="specificationKey" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
在这段Schema描述中,描述了compliantSpecBag这个元素类型,任何使用compliantSpecBag类型的元素可以包含的元素是specification,这个元素可以出现0次到无穷次(无限制,事实上不可能出现无穷次),而specification这个元素中包含一个属性specificationKey,该属性是必须的,同时类型为字符串(xs:string)。xs这个命名空间是W3CXMLSchema2001的命名空间(namespace)。
<xs:complexType name="featureBag">
<xs:sequence>
<xs:element name="feature" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
在这里,描述了featureBag这个元素类型,任何使用featureBag类型的文档元素可以包含的子元素是feature,而feature元素能够出现0次到无穷次(无限制,事实上不可能出现无穷次)。该元素的内容的类型是字符串(xs:string)。
<xs:complexType name="parameter">
<xs:sequence>
<xs:element name="keyName" type="xs:string"/>
<xs:element name="keyValue" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="parameterBag">
<xs:sequence>
<xs:element name="parameter" type="parameter" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
这里首先描述了parameter这个元素类型,任何使用parameter类型的文档元素可以包含的子元素有两个keyName和keyValue,它们都是必须出现的子元素,同时仅可出现一次。他们的类型也都是字符串(xs:string)。然后描述的是parameterBag元素类型,任何使用parameterBag类型的文档元素可以包含的子元素是parameter,而这个子元素的类型是先前定义的parameter(在XMLSchema中,类型名和元素名的域空间是正交的,不需要考虑任何的名字重复问题),parameter元素出现的次数可以是从0次到无穷次。
<xs:complexType name="product">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="compliantSpecBag" type="compliantSpecBag"/>
<xs:element name="featureBag" type="featureBag"/>
<xs:element name="parameterBag" type="parameterBag"/>
</xs:sequence>
<xs:attribute name="productKey" type="xs:string" use="required"/>
<xs:attribute name="parentCategoryKey" type="xs:string" use="required"/>
</xs:complexType>
这里描述了product这个元素类型,任何使用product类型的文档元素可以包含的子元素是name、description、compliantSpecBag、featureBag、parameterBag。name和description元素的类型都是xs:string。而compliantSpecBag、featureBag、parameterBag的类型大家通过查看这断XMLSchema定义也可以很清楚地发现是引用了前面定义的这些类型定义。任何使用product类型的文档元素还有两个必须出现的属性productKey和parentCategoryKey,这是两个字符串(xs:string)类型的属性值,分别表示了自身元素的键值和父辈category的键值。
<xs:complexType name="category">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="product" type="product" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="categoryKey" type="xs:string" use="required"/>
<xs:attribute name="parentCategoryKey" type="xs:string" use="required"/>
</xs:complexType>
这是category元素类型的描述,任何使用product类型的文档元素可以包含的子元素是name、description、category和product。name和description元素的类型都是简单类型xs:string。而category是一个递归元素,引用了自身这个元素类型。而product的元素类型则是前面描述好的product类型。任何使用product类型的文档元素还有两个必须出现的属性categoryKey和parentCategoryKey,这是两个字符串(xs:string)类型的属性值,分别表示了自身元素的键值和父辈category的键值。
<xs:element name="save_category">
<xs:complexType>
<xs:sequence>
<xs:element name="authInfo" type="xs:base64Binary"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
这是在这个Schema文档中唯一的一个元素定义,元素save_category是一个复合类型,它的元素可以有authInfo和category。其中authInfo是一个base64编码的字符串,而category则是一个可以出现0次到无限次的类型为category的子元素。我们不难发现元素定义和类型定义的基本机制是一样的,事实上,我们完全可以将这段定义拆分成两段,一段为类型定义,一段为元素定义,下面给出这个等价实例,希望有助于对Schema的理解。
<xs:complexType name="save_category">
<xs:sequence>
<xs:element name="authInfo" type="xs:base64Binary"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="save_category" type="save_category" />
那为什么要采用第一种方法,而不使用第二种方法呢,原因也很简单,由于整个Web服务相关的消息Schema中,诸如category、product、featureBag、compliantSpecBag、parameterBag这些元素都可能被复用,因此定义成类型比较合适,而save_category是一个单一的消息,不可能被其他元素复用,因此就直接定义成了元素。
</xs:schema>
最后,我给出对应本节描述的save_category元素的Schema定义的Schema图示来结束本小节。
Figure1.SOAPAPISchema图示
WSDL服务描述
对SOAPAPI消息完成Schema建模之后,一方面这个数据模型可以由SOAPInterface来使用,当发生具体调用时可以使用这个数据模型来除了传入的参数并生成传出的参数。同时,利用这个数据模型,我们可以生成相应的WSDL描述,从而将这个Web服务的接口文档发布给使用者,该接口文档是具备被程序自动处理的能力的。
以下是WSDL文档详细的定义:(完整的WSDL文档是:sagitta.wsdl)
<?xml version="1.0"?>
<definitions name="catalogService"
targetNamespace="http://www.sagitta.com/wsdl/savecategory.wsdl"
xmlns:tns="http://www.sagitta.com/wsdl/savecategory.wsdl"
xmlns:myxs="http://www.sagitta.com/schema/"
xmlns:soap="http://www.w3.org/2001/06/soap-envelope"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<import namespace="http://www.sagitta.com/schema/"
location=" http://www.sagitta.com/schema/save_category.xsd" />
这是WSDL文件的文件头,其中的import元素指明在这个WSDL文件中,types系统是由http://www.sagitta.com/schema/save_category.xsd文件具体描述,在这里仅仅是将其导入。
<message name="save_category">
<part name="body" element="myxs:save_category"/>
</message>
<message name="categoryList">
<part name="body" element="myxs:categoryList"/>
</message>
这里定义了两条消息:save_category消息,在前面的Schema建模中已经完整地创建了根元素的结构定义。其中myxs是这里使用的命名空间(namespace),命名空间的具体定义在文件头上出现。而categoryList将会对应save_category消息的返回消息,在Schema建模中没有表现,在这里我也仅列出一个元素名,相信大家在看了本文的前半部分以及本系列的前一篇文章之后,会很清楚如何来定义。
<portType name="save_category_portType">
<operation name="save_category_operation">
<input message="tns:save_category"/>
<output message="tns:categoryList"/>
</operation>
</portType>
这部分定义了服务访问点的调用模式的类型,表明这个入口类型是请求/响应模式,请求消息是save_category,而响应消息是categoryList。
<binding name="save_category_soapBinding" type=" save_category_portType ">
<soap:binding style="document" transport=" http://www.w3.org/2001/06/soap-envelope/http">
<operation name="save_category_operation">
<soap:operation soapAction=" http://www.sagitta.com/catalog/">
<input>
<soap:body use="literal" namespace=" http://www.sagitta.com/schema/"
encodingStyle=" http://www.w3.org/2001/06/soap-encoding"/>
</input>
<output>
<soap:body use="literal" namespace=" http://www.sagitta.com/schema/"
encodingStyle=" http://www.w3.org/2001/06/soap-encoding"/>
</output>
</soap:operation>
</operation>
</soap:binding>
</binding>
这部分将服务访问点的抽象定义与SOAPHTTP绑定,描述如何通过SOAP/HTTP来访问按照前面描述的访问入口点类型部署的访问入口。其中规定了在具体SOAP调用时,应当使用的soapAction是"http://www.sagitta.com/catalog/",而请求/响应消息的编码风格都应当采用SOAP规范默认定义的编码风格"http://www.w3.org/2001/06/soap-encoding"。
<service name="catalogService">
<documentation>Online Web Service for Catalog</documentation>
<port name="save_category_port" binding="tns:save_category_soapBinding">
<soap:address location="http://www.sagitta.com/catalog/"/>
</port>
</service>
</definitions>
这部分是具体的Web服务的定义,在这个名为catalogService的Web服务中,提供了一个服务访问入口(其实还有很多,不过在这里因为演示的原因,仅仅介绍了一个),访问地址是"http://www.sagitta.com/catalog/",使用的消息模式是由前面的binding所定义的。
UDDI服务发布
在前一节中,我们已经通过使用WSDL这个工具将CatalogService这个Web服务进行了结构化地描述。为了使更多的潜在用户能够发现这个Web服务,同时也为了加强这个Web服务的互操作能力和灾难恢复时的连接保持能力,我们需要使用UDDISDK将这个Web服务注册到UDDI注册中心中去。
假设我们之前已经注册了一个businessEntity,叫做www.sagitta.com,一个在线服务提供商,这个businessEntity的键值是"434554F4-6E17-1342-EA41-36E642531DA1",那么我们要在这个businessEntity下注册一个businessService,以用于描述前面的CatalogService。同时需要成立的假设是我们也预先注册了一个ServiceType(tModel),这个tModel描述了我们这个需要发布的Web服务的调用规范,具体内容是前面我定义的这个WSDL文档,在UDDI中,注册的是描述的链接。
businessService注册的SOAP消息如下,其中使用了Microsoft的test.uddi.microsoft.com站点,因此authInfo中可以填入测试用的udditest。
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<save_service generic="1.0" xmlns="urn:uddi-org:api">
<authInfo>udditest</authInfo>
<businessService businessKey="434554F4-6E17-1342-EA41-36E642531DA1" serviceKey="">
<name>categoryService</name>
<description xml:lang="en">Online Web Service for Catalog</description>
<bindingTemplates>
<bindingTemplate bindingKey="" serviceKey="">
<description xml:lang="en">categoryService's BindingTemplate3</description>
<accessPoint URLType="http">http://www.sagitta.com/catalog/</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:E31A569A-AEFF-4468-BA4D-2BF22FE4ACEF">
<description xml:lang="en">Sagitta Web Service Type Description</description>
<instanceDetails>
<description xml:lang="en">Sagitta Web Service Type Description</description>
<overviewDoc>
<description xml:lang="en">Sagitta Web Service Overview</description>
<overviewURL>http://www.sagitta.com/wsdl/savecategory.wsdl</overviewURL>
</overviewDoc>
</instanceDetails>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
</businessService>
</save_service>
</Body>
</Envelope>
通过上述的API调用,我们就已经把这个服务注册进了UDDI注册中心,其中bindingTemplate的accessPoint是服务的入口,而overviewDoc中的overviewURL是WSDL文档的访问位置。
潜在的使用者可以通过查询UDDI注册中心找到这个Web服务,通过overviewURL中保存的URL找到服务的描述,然后通过accessPoint所指定的访问地址来访问这个服务。
当发生紧急服务崩溃的时候,Web服务可能被迁移到另一台主机上,IP地址,甚至是访问的URL都可能有很大变化,此时原先的集成的连接将不再工作。但是由于UDDI注册的存在,我们可以通过自动化的程序手段来解决这个问题,使得类似的服务灾难恢复的过程非常迅速。
具体的流程一般是:
•当恢复的服务启动后,自动去更新UDDI注册中心上的数据,将访问入口修改到新的URL位置;
•连入的客户端系统当发现无法访问最终服务的时候,将会定期去查询UDDI注册中心,看看新的BindingTemplate数据和本地缓存的有没有差别,如果有的话,就下载到本地,重新建立服务绑定,完成服务连接的迁移。
总结
到这篇文章为止,如何架构WebService这个系列就将告一段落,在整个系列中,从为什么要有Web服务开始,到什么是Web服务,Web服务的开发工具,对Web服务作了一个概念上的全面介绍。然后以一个具体实例来介绍Web服务的构建模式和各种WebService"stack"技术的具体应用。希望这个系列对大家理解和接受下一代的应用包装模式Web服务有一个全面的帮助。
参考资料
•WebService技术/评论网站 •UDDI-China.ORG,以UDDI为主的Web服务技术网站。
•WebServices.ORG,Web服务的综合类技术网站。
•IBMdeveloperWorks/WebServiceZone,IBM的Web服务技术资源中心
•MSDNOnlineWebServicesDeveloperResources,Microsoft的Web服务的开发者资源网站
•ITPapers/WebService,ITPapers的Web服务评论文章
•解决B2B电子商务应用交互和集成的InterOPStack系列技术标准规范 •UDDI执行白皮书,UDDI-China.org,UDDI.org
•UDDI技术白皮书,UDDI-China.org,UDDI.org
•UDDI程序员API规范,UDDI-China.org,UDDI.org
•UDDI数据结构参考,UDDI-China.org,UDDI.org
•WebServiceDescriptionLanguage(WSDL)1.0,IBM,25Sep2000
•asp">SOAP:SimpleObjectAccessProtocolSpecification1.1,IBM,Microsoft,DevelopMentor,2000
•XMLSchemaPart0:Primer,W3C,2May2001
•ExtensibleMarkupLanguage(XML)1.0(SecondEdition),W3C,6Oct2000
•架构Webservices系列 •架构WebService(一):为什么需要Web服务
•架构WebService(二):什么是Web服务
•架构WebService(三):基于Web服务的应用、解决方案和开发平台
•架构WebService(四):实战Web服务
•架构WebService(五):交互界面,Web服务定义的核心
作者简介
柴晓路:上海得易电子商务技术有限公司(DealEasy)首席系统架构师、XML技术顾问。UDDI-China.org蓝色火焰工作室(BlueBlazeStudio)成员。UDDIAdvisorGroup成员,WSUIWorkingGroup成员。2000年获复旦大学计算机科学硕士学位,曾在国际计算机科学学术会议(ICSC)、亚太区XML技术研讨会(XMLAsia/Pacific'99)、中国XML技术研讨会(北京)、计算机科学期刊等各类国际、国内重要会议与期刊上发表论文多篇。专长于基于XML的系统集成和数据交换的技术研究,同时对数据库、面向对象技术及CSCW等技术比较擅长。
本文是架构Web服务的系列文章的第六篇,也是最后一篇,文本以前文为基础,在前文的应用实例的基础上,考察了发布Web服务界面的整个过程:XMLSchema建模、WSDL发布和UDDI注册。通过本文,大家可以详细具体地了解各个XML和WebService的系列规范在WebService的发布时所起的左右,对WebService技术也将有一个深入的理解。
在前文中,我已经介绍过,Web服务是通过SOAP消息调用的,通过WSDL进行界面描述的,以及通过UDDI进行公共注册发布的。在前一篇文章中,我已经介绍了如何进行SOAPAPI的消息定义,那么在本文中,我将单把save_category提出来,看看在具体的实现上,应当如何对这个消息使用W3CXMLSchema进行建模,如果使用WSDL将基于该消息调用的Web服务进行规范描述并交付调用者,以及如何将这个Web服务连同它的WSDL规范化描述文件一起发布到UDDI注册中心中去。希望大家能通过本文的实例讲解,在本系列的最后完整地了解Web服务的工作原理和相关技术规范的作用。
本文所引用的资源主要包括两类,一类是Web服务的技术资源网站,包含了大量Web服务的技术信息,另一类是Web服务“stack"系列技术规范,他们是一个整体的技术体系,包括UDDI、SOAP、WSDL、XMLSchema,XML等。本文的最后给出了这些资源的链接,有兴趣的读者可以通过这些资源链接找到所需的内容。
SOAP消息示例
以下是一个save_category的调用例子,在例子中使用了SOAPHTTPBinding(使用的SOAP规范的版本是1.2),假设目标Web服务被部署在www.sagitta.com,而调用的Web服务的入口位置将是http://www.sagitta.com/catalog/。
在这个消息中,将在一个现有的category中添加一个新的category和一个新的product。
POST /catalog HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://www.sagitta.com/catalog/"
Host: www.sagitta.com
<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Body>
<save_category xmlns="http://www.sagitta.com/schema/">
<authInfo>5Az784kJceHCE982eB</authInfo>
<category categoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073"
parentCategoryKey="ab4e3de1-7865-f2c1-b49a-beccbd21c072">
<name>Consumer Electronics</name>
<description>Product Category for Consumer Electronics </description>
<category categoryKey="" parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073">
<name>SONY Consumer Electronics</name>
<description>Sony's Product Category for Consumer Electronics</description>
</category>
<product productKey="" parentCategoryKey=" cb4e17d1-6100-47f6-a532-cd9cbd30c073">
<name>DSC-S75 Digital Camera</name>
<description>Sony's Brand-New Professional Digital Camera</description>
<compliantSpecBag>
<specification specificationKey="Key[USB1.1]" />
</compliantSpecBag>
<featureBag>
<feature>……</feature>
<feature>……</feature>
</featureBag>
<parameterBag>
……
</parameterBag>
</product>
</category>
</save_category>
</env:Body>
</env:Envelope>
该调用消息的返回消息可能是:
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Body>
<categoryList xmlns="http://www.sagitta.com/schema/">
<category categoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073"
parentCategoryKey="ab4e3de1-7865-f2c1-b49a-beccbd21c072">
<category categoryKey="8933aa50-3aaf-11d5-80dc-002035229c64"
parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073" />
<product productKey="89307600-3aaf-11d5-80dc-002035229c64"
parentCategoryKey="cb4e17d1-6100-47f6-a532-cd9cbd30c073" />
</category>
</categoryList>
</env:Body>
</env:Envelope>
从中我们可以看到在save_category和categoryList两个元素后面都带了一个xmlns的修饰"http://www.sagitta.com/schema/"。这URI唯一表示了该元素及其所有子元素的的命名空间。同时通过这个URL可以获得这些元素的Schema定义。
使用W3CXMLSchema描述的XML文档的模式定义在整个Web服务的技术系列中处于一个支持工具的地位。W3CXMLSchema是任何类型的XML文档的建模工具。在Web服务体系中,无论在SOAP消息的表示上,还是在WSDL的界面描述上,XMLSchema都是不可缺少的重要工具和底层支持。
下面我将从XMLSchema开始,针对save_category这个消息(同时也对应一个服务入口)逐一介绍如何为我们的XML消息进行XMLSchema建模,如何使用WSDL将save_category这个服务入口进行界面描述,然后将这个入口发布到UDDI注册中心中去。
XMLSchema建模
XMLSchema的文件后缀是.xsd文件,一个XMLSchema中的定义通常分为两部分,型(Type)定义和元素(Element)定义。下面我们结合save_category具体的XMLSchema定义来说明如何使用XMLSchema来实现模式定义。
在下面的XMLSchema文档中,型定义包括:compliantSpecBag,featureBag,parameter,parameterBag,product和category六个类型,而元素定义为save_category这一个元素。
save_category的XMLSchema描述定义:(完整的XMLSchema文档是:sagitta.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
以上是XMLSchema的文件头。
<xs:complexType name="compliantSpecBag">
<xs:sequence>
<xs:element name="specification" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="specificationKey" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
在这段Schema描述中,描述了compliantSpecBag这个元素类型,任何使用compliantSpecBag类型的元素可以包含的元素是specification,这个元素可以出现0次到无穷次(无限制,事实上不可能出现无穷次),而specification这个元素中包含一个属性specificationKey,该属性是必须的,同时类型为字符串(xs:string)。xs这个命名空间是W3CXMLSchema2001的命名空间(namespace)。
<xs:complexType name="featureBag">
<xs:sequence>
<xs:element name="feature" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
在这里,描述了featureBag这个元素类型,任何使用featureBag类型的文档元素可以包含的子元素是feature,而feature元素能够出现0次到无穷次(无限制,事实上不可能出现无穷次)。该元素的内容的类型是字符串(xs:string)。
<xs:complexType name="parameter">
<xs:sequence>
<xs:element name="keyName" type="xs:string"/>
<xs:element name="keyValue" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="parameterBag">
<xs:sequence>
<xs:element name="parameter" type="parameter" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
这里首先描述了parameter这个元素类型,任何使用parameter类型的文档元素可以包含的子元素有两个keyName和keyValue,它们都是必须出现的子元素,同时仅可出现一次。他们的类型也都是字符串(xs:string)。然后描述的是parameterBag元素类型,任何使用parameterBag类型的文档元素可以包含的子元素是parameter,而这个子元素的类型是先前定义的parameter(在XMLSchema中,类型名和元素名的域空间是正交的,不需要考虑任何的名字重复问题),parameter元素出现的次数可以是从0次到无穷次。
<xs:complexType name="product">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="compliantSpecBag" type="compliantSpecBag"/>
<xs:element name="featureBag" type="featureBag"/>
<xs:element name="parameterBag" type="parameterBag"/>
</xs:sequence>
<xs:attribute name="productKey" type="xs:string" use="required"/>
<xs:attribute name="parentCategoryKey" type="xs:string" use="required"/>
</xs:complexType>
这里描述了product这个元素类型,任何使用product类型的文档元素可以包含的子元素是name、description、compliantSpecBag、featureBag、parameterBag。name和description元素的类型都是xs:string。而compliantSpecBag、featureBag、parameterBag的类型大家通过查看这断XMLSchema定义也可以很清楚地发现是引用了前面定义的这些类型定义。任何使用product类型的文档元素还有两个必须出现的属性productKey和parentCategoryKey,这是两个字符串(xs:string)类型的属性值,分别表示了自身元素的键值和父辈category的键值。
<xs:complexType name="category">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="product" type="product" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="categoryKey" type="xs:string" use="required"/>
<xs:attribute name="parentCategoryKey" type="xs:string" use="required"/>
</xs:complexType>
这是category元素类型的描述,任何使用product类型的文档元素可以包含的子元素是name、description、category和product。name和description元素的类型都是简单类型xs:string。而category是一个递归元素,引用了自身这个元素类型。而product的元素类型则是前面描述好的product类型。任何使用product类型的文档元素还有两个必须出现的属性categoryKey和parentCategoryKey,这是两个字符串(xs:string)类型的属性值,分别表示了自身元素的键值和父辈category的键值。
<xs:element name="save_category">
<xs:complexType>
<xs:sequence>
<xs:element name="authInfo" type="xs:base64Binary"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
这是在这个Schema文档中唯一的一个元素定义,元素save_category是一个复合类型,它的元素可以有authInfo和category。其中authInfo是一个base64编码的字符串,而category则是一个可以出现0次到无限次的类型为category的子元素。我们不难发现元素定义和类型定义的基本机制是一样的,事实上,我们完全可以将这段定义拆分成两段,一段为类型定义,一段为元素定义,下面给出这个等价实例,希望有助于对Schema的理解。
<xs:complexType name="save_category">
<xs:sequence>
<xs:element name="authInfo" type="xs:base64Binary"/>
<xs:element name="category" type="category" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="save_category" type="save_category" />
那为什么要采用第一种方法,而不使用第二种方法呢,原因也很简单,由于整个Web服务相关的消息Schema中,诸如category、product、featureBag、compliantSpecBag、parameterBag这些元素都可能被复用,因此定义成类型比较合适,而save_category是一个单一的消息,不可能被其他元素复用,因此就直接定义成了元素。
</xs:schema>
最后,我给出对应本节描述的save_category元素的Schema定义的Schema图示来结束本小节。
Figure1.SOAPAPISchema图示
WSDL服务描述
对SOAPAPI消息完成Schema建模之后,一方面这个数据模型可以由SOAPInterface来使用,当发生具体调用时可以使用这个数据模型来除了传入的参数并生成传出的参数。同时,利用这个数据模型,我们可以生成相应的WSDL描述,从而将这个Web服务的接口文档发布给使用者,该接口文档是具备被程序自动处理的能力的。
以下是WSDL文档详细的定义:(完整的WSDL文档是:sagitta.wsdl)
<?xml version="1.0"?>
<definitions name="catalogService"
targetNamespace="http://www.sagitta.com/wsdl/savecategory.wsdl"
xmlns:tns="http://www.sagitta.com/wsdl/savecategory.wsdl"
xmlns:myxs="http://www.sagitta.com/schema/"
xmlns:soap="http://www.w3.org/2001/06/soap-envelope"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<import namespace="http://www.sagitta.com/schema/"
location=" http://www.sagitta.com/schema/save_category.xsd" />
这是WSDL文件的文件头,其中的import元素指明在这个WSDL文件中,types系统是由http://www.sagitta.com/schema/save_category.xsd文件具体描述,在这里仅仅是将其导入。
<message name="save_category">
<part name="body" element="myxs:save_category"/>
</message>
<message name="categoryList">
<part name="body" element="myxs:categoryList"/>
</message>
这里定义了两条消息:save_category消息,在前面的Schema建模中已经完整地创建了根元素的结构定义。其中myxs是这里使用的命名空间(namespace),命名空间的具体定义在文件头上出现。而categoryList将会对应save_category消息的返回消息,在Schema建模中没有表现,在这里我也仅列出一个元素名,相信大家在看了本文的前半部分以及本系列的前一篇文章之后,会很清楚如何来定义。
<portType name="save_category_portType">
<operation name="save_category_operation">
<input message="tns:save_category"/>
<output message="tns:categoryList"/>
</operation>
</portType>
这部分定义了服务访问点的调用模式的类型,表明这个入口类型是请求/响应模式,请求消息是save_category,而响应消息是categoryList。
<binding name="save_category_soapBinding" type=" save_category_portType ">
<soap:binding style="document" transport=" http://www.w3.org/2001/06/soap-envelope/http">
<operation name="save_category_operation">
<soap:operation soapAction=" http://www.sagitta.com/catalog/">
<input>
<soap:body use="literal" namespace=" http://www.sagitta.com/schema/"
encodingStyle=" http://www.w3.org/2001/06/soap-encoding"/>
</input>
<output>
<soap:body use="literal" namespace=" http://www.sagitta.com/schema/"
encodingStyle=" http://www.w3.org/2001/06/soap-encoding"/>
</output>
</soap:operation>
</operation>
</soap:binding>
</binding>
这部分将服务访问点的抽象定义与SOAPHTTP绑定,描述如何通过SOAP/HTTP来访问按照前面描述的访问入口点类型部署的访问入口。其中规定了在具体SOAP调用时,应当使用的soapAction是"http://www.sagitta.com/catalog/",而请求/响应消息的编码风格都应当采用SOAP规范默认定义的编码风格"http://www.w3.org/2001/06/soap-encoding"。
<service name="catalogService">
<documentation>Online Web Service for Catalog</documentation>
<port name="save_category_port" binding="tns:save_category_soapBinding">
<soap:address location="http://www.sagitta.com/catalog/"/>
</port>
</service>
</definitions>
这部分是具体的Web服务的定义,在这个名为catalogService的Web服务中,提供了一个服务访问入口(其实还有很多,不过在这里因为演示的原因,仅仅介绍了一个),访问地址是"http://www.sagitta.com/catalog/",使用的消息模式是由前面的binding所定义的。
UDDI服务发布
在前一节中,我们已经通过使用WSDL这个工具将CatalogService这个Web服务进行了结构化地描述。为了使更多的潜在用户能够发现这个Web服务,同时也为了加强这个Web服务的互操作能力和灾难恢复时的连接保持能力,我们需要使用UDDISDK将这个Web服务注册到UDDI注册中心中去。
假设我们之前已经注册了一个businessEntity,叫做www.sagitta.com,一个在线服务提供商,这个businessEntity的键值是"434554F4-6E17-1342-EA41-36E642531DA1",那么我们要在这个businessEntity下注册一个businessService,以用于描述前面的CatalogService。同时需要成立的假设是我们也预先注册了一个ServiceType(tModel),这个tModel描述了我们这个需要发布的Web服务的调用规范,具体内容是前面我定义的这个WSDL文档,在UDDI中,注册的是描述的链接。
businessService注册的SOAP消息如下,其中使用了Microsoft的test.uddi.microsoft.com站点,因此authInfo中可以填入测试用的udditest。
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<save_service generic="1.0" xmlns="urn:uddi-org:api">
<authInfo>udditest</authInfo>
<businessService businessKey="434554F4-6E17-1342-EA41-36E642531DA1" serviceKey="">
<name>categoryService</name>
<description xml:lang="en">Online Web Service for Catalog</description>
<bindingTemplates>
<bindingTemplate bindingKey="" serviceKey="">
<description xml:lang="en">categoryService's BindingTemplate3</description>
<accessPoint URLType="http">http://www.sagitta.com/catalog/</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:E31A569A-AEFF-4468-BA4D-2BF22FE4ACEF">
<description xml:lang="en">Sagitta Web Service Type Description</description>
<instanceDetails>
<description xml:lang="en">Sagitta Web Service Type Description</description>
<overviewDoc>
<description xml:lang="en">Sagitta Web Service Overview</description>
<overviewURL>http://www.sagitta.com/wsdl/savecategory.wsdl</overviewURL>
</overviewDoc>
</instanceDetails>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
</businessService>
</save_service>
</Body>
</Envelope>
通过上述的API调用,我们就已经把这个服务注册进了UDDI注册中心,其中bindingTemplate的accessPoint是服务的入口,而overviewDoc中的overviewURL是WSDL文档的访问位置。
潜在的使用者可以通过查询UDDI注册中心找到这个Web服务,通过overviewURL中保存的URL找到服务的描述,然后通过accessPoint所指定的访问地址来访问这个服务。
当发生紧急服务崩溃的时候,Web服务可能被迁移到另一台主机上,IP地址,甚至是访问的URL都可能有很大变化,此时原先的集成的连接将不再工作。但是由于UDDI注册的存在,我们可以通过自动化的程序手段来解决这个问题,使得类似的服务灾难恢复的过程非常迅速。
具体的流程一般是:
•当恢复的服务启动后,自动去更新UDDI注册中心上的数据,将访问入口修改到新的URL位置;
•连入的客户端系统当发现无法访问最终服务的时候,将会定期去查询UDDI注册中心,看看新的BindingTemplate数据和本地缓存的有没有差别,如果有的话,就下载到本地,重新建立服务绑定,完成服务连接的迁移。
总结
到这篇文章为止,如何架构WebService这个系列就将告一段落,在整个系列中,从为什么要有Web服务开始,到什么是Web服务,Web服务的开发工具,对Web服务作了一个概念上的全面介绍。然后以一个具体实例来介绍Web服务的构建模式和各种WebService"stack"技术的具体应用。希望这个系列对大家理解和接受下一代的应用包装模式Web服务有一个全面的帮助。
参考资料
•WebService技术/评论网站 •UDDI-China.ORG,以UDDI为主的Web服务技术网站。
•WebServices.ORG,Web服务的综合类技术网站。
•IBMdeveloperWorks/WebServiceZone,IBM的Web服务技术资源中心
•MSDNOnlineWebServicesDeveloperResources,Microsoft的Web服务的开发者资源网站
•ITPapers/WebService,ITPapers的Web服务评论文章
•解决B2B电子商务应用交互和集成的InterOPStack系列技术标准规范 •UDDI执行白皮书,UDDI-China.org,UDDI.org
•UDDI技术白皮书,UDDI-China.org,UDDI.org
•UDDI程序员API规范,UDDI-China.org,UDDI.org
•UDDI数据结构参考,UDDI-China.org,UDDI.org
•WebServiceDescriptionLanguage(WSDL)1.0,IBM,25Sep2000
•asp">SOAP:SimpleObjectAccessProtocolSpecification1.1,IBM,Microsoft,DevelopMentor,2000
•XMLSchemaPart0:Primer,W3C,2May2001
•ExtensibleMarkupLanguage(XML)1.0(SecondEdition),W3C,6Oct2000
•架构Webservices系列 •架构WebService(一):为什么需要Web服务
•架构WebService(二):什么是Web服务
•架构WebService(三):基于Web服务的应用、解决方案和开发平台
•架构WebService(四):实战Web服务
•架构WebService(五):交互界面,Web服务定义的核心
作者简介
柴晓路:上海得易电子商务技术有限公司(DealEasy)首席系统架构师、XML技术顾问。UDDI-China.org蓝色火焰工作室(BlueBlazeStudio)成员。UDDIAdvisorGroup成员,WSUIWorkingGroup成员。2000年获复旦大学计算机科学硕士学位,曾在国际计算机科学学术会议(ICSC)、亚太区XML技术研讨会(XMLAsia/Pacific'99)、中国XML技术研讨会(北京)、计算机科学期刊等各类国际、国内重要会议与期刊上发表论文多篇。专长于基于XML的系统集成和数据交换的技术研究,同时对数据库、面向对象技术及CSCW等技术比较擅长。
发表评论
-
CXF中WS-Security自编码实现[转]
2013-11-19 14:20 632最近在做一个项目,两 ... -
cxf动态调用webservice设置超时,测试线程安全[转]
2013-11-05 15:21 1023Java代码 import java. ... -
开发高性能的WebService应用
2013-11-05 15:19 639一、 WebService概述 1、 性能 -
[转]Spring下设置CXF的WebService客户端超时时长
2013-09-23 14:45 903主要在客户端调用时设置 : 在使用WebServ ... -
[转]Essential Security Tools: OpenSSL and Keytool
2013-09-05 20:05 743See also: <<Essential Se ... -
[转] 密钥库文件格式【Keystore】
2013-09-05 19:17 1100密钥库文件格式【Keysto ... -
【转】Apache CXF
2013-09-03 15:27 8131.http://www.ibm.com/developer ... -
[转]cxf+spring实现ws-security的数字证书验证方式
2013-09-03 14:31 867第一步 生成可用的数 ... -
[转]cxf开发webservice生成数字安全证书
2013-08-28 10:41 786分别生成服务端:serverStore.jks,clien ... -
WSDL详解
2013-08-23 12:04 467WSDL (Web Services Description ... -
WebService 安全 WS-Security
2013-08-23 11:58 650WS-Security WS-Security(W ... -
WSDL编写的五个步骤
2013-08-23 11:15 732说明:本文意译自BPEL1.1规范16.2节。 本文讨论一 ... -
AXIS2之WSDL2JAVA
2013-08-22 17:02 797WSDL2Java操作指南 1. 安装JDK1.5, 配置 ... -
WSDL的建模与解析
2013-08-22 09:52 517对于 WSDL 解析,有如下 3 种基本方法: 1. ... -
用Soap消息调用Web Services
2013-08-21 10:57 581如何使用用于 XML 消息传递的 Java API(Java ... -
Web Service开发指南
2012-10-11 10:24 697开发说明: 1. 创建Web Service,并编译: 开 ... -
[原]WebService应用场合
2012-10-11 10:01 672本文转载,推荐给和我 ... -
CXF wsdl2Java
2012-09-26 16:56 706一. 简介 Apache CXF 是一个Service框架, ...
相关推荐
OIR是存储与Web服务相关的元数据的地方,包括服务描述、操作定义等。在给定的文件内容中,可以看到通过调用`ad_pa_insert_package`过程来插入产品信息,这实际上是在OIR中注册新的Web服务。具体地,`insert_ad_pm_...
注册过程中,需要提供WebService的详细描述信息,包括服务的名称、位置(URL),以及它能提供的操作和功能描述。 在SAP的上下文中,发布BW Query到UDDI Registry涉及使用SAP NetWeaver平台的相关技术。SAP ...
【标题】:“xfire发布webservice服务” 在Java开发中,XFire是一个早期流行的Web服务框架,用于创建和消费Web服务。XFire是Apache CXF的前身,它提供了简单、高性能的方式来实现基于SOAP的Web服务。这篇博客文章...
标题中的“axis发布webservice的步骤”涉及到的是在Java环境中使用Apache Axis库创建并部署Web服务的过程。Apache Axis是开源的Web服务工具包,它允许开发者通过简单的API将Java类暴露为Web服务,或者调用远程Web...
#### WebService描述:WSDL(Web Services Description Language) WSDL是一种XML格式的语言,用于描述WebService。它定义了服务的协议、数据及其位置,并将服务描述为一组对消息进行操作的网络端点。WSDL文档可以...
3. 注册服务:使用`@WebService`注解的`endpointInterface`属性指定SEI的全限定名,并将服务实例暴露给JAX-WS运行时。 ```java @WebService(endpointInterface = "com.example.HelloWorld") public class ...
WebService使用XML(可扩展标记语言)作为数据交换格式,通过SOAP(简单对象访问协议)进行通信,依赖于WSDL(Web服务描述语言)来定义服务接口,而UDDI(统一描述、发现和集成)则用于服务的发布和查找。...
2. **生成WSDL**:WSDL(Web Services Description Language)文件描述了Web服务的接口、操作、消息格式等。在Websphere中,可以自动生成WSDL,或者手动编写。通过右键点击服务类,选择“生成WSDL”选项即可。 3. *...
在Jetty中,Servlet可以通过`web.xml`部署描述符进行配置,或者使用Java代码动态注册。本项目可能使用了注解驱动的Servlet配置,通过`@WebServlet`注解定义Servlet类及其映射路径。 4. 跨域支持: 跨域资源共享...
3. **服务描述语言(WSDL)**:一种XML格式的文件,用于描述服务接口、消息格式以及如何与服务交互等信息。 4. **服务注册中心**:如UDDI(Universal Description, Discovery and Integration),用于注册和发现服务的...
【标题】: 使用XFire发布WebService 在Web服务的世界中,XFire是一个强大的开源框架,它使得开发和部署Web...通过理解并实践本教程,开发者可以更好地掌握Web服务的发布与调用技术,以及如何利用XFire提升开发效率。
4. UDDI(统一描述、发现和集成):UDDI是一个标准的目录服务,用于发布和查找WebService。服务提供商可以在UDDI注册他们的服务,而消费者则可以通过UDDI查询并找到所需的服务。 现在,我们来看看"WebServiceStudio...
企业可以通过UDDI注册自己的WebService,其他开发者则可以通过查询UDDI找到所需的服务。 5. **C#与WebService**: 在C#中,我们使用`System.Web.Services`命名空间来创建和实现WebService。一个基本的WebService类会...
4. UDDI:UDDI(通用描述、发现与集成)是一个基于 XML 的协议,用于发布和查找 WebService。服务提供者可以将他们的 WebService 注册到 UDDI 注册中心,以便其他开发者可以搜索并使用这些服务。 现在,让我们来看...
3. UDDI(Universal Description, Discovery, and Integration):UDDI是一个标准的目录服务,用于发布和查找WebService。开发者可以在这里注册他们的服务,以便其他开发者可以发现并使用。 在"webService接口app...
3. UDDI(Universal Description, Discovery, and Integration):是服务注册和发现的机制,允许服务提供商发布他们的服务,而消费者可以查找并使用这些服务。 二、WebService与SQL的结合 1. 数据库访问:通过SOAP...
UDDI可以被看作一个在线的业务注册中心,企业可以在此发布自己的WebService信息,其他企业或个人可以通过UDDI查找所需的服务。UDDI包括了一系列标准的接口,用于Web服务的注册、发现和集成。它定义了以下核心概念:...