UDDI 数据结构
为了开始将公司添加到 UDDI 注册中心,Francis 定义了要输入注册中心的信息。
businessEntity
第一步是将报社本身的信息输入注册中心。为此,Francis 创建了一个 businessEntity
对象。此对象包含有关企业的信息,既用于对企业进行标识,也用于提供与其有关的信息。例如,businessEntity 对象可以包含多个名称(从而能够为公司所使用的每种语言创建一个 name 元素),联系信息(Francis 被告知将 Pat Mooney 添加为主要联系人)、与实体相关的服务(Gene 将稍后添加)和用于对公司进行标识与分类的信息。
尽管大部分人都不会采用这种方式与 UDDI 注册中心交互,但要注意的一个事实是,UDDI 实际上就是 SOAP 应用程序;执行的所有操作都作为往返传递 SOAP 消息的结果发生。这意味着,Francis 所创建的 businessEntity 最终将表示为 XML 元素。请参见清单 2。
清单 2. businessEntity 元素
<businessEntity businessKey="{uuid}" operator="(optional)" authorizedName="(optional)"> <discoveryURLs> <discoveryURL></discoveryURL> <discoveryURL></discoveryURL> </discoveryURLs> <name>The Daily Moon</name> <name lang="fr-ca">La Lune Quotidienne</name> <description></description> <contacts> <contact> <description></description> <personName>Pat Mooney</personName> <phone></phone> <email>[email protected]</email> <address useType="optional, billing, etc." sortCode="optional" tModelKey="optional"> <addressLine></addressLine> <addressLine></addressLine> <addressLine></addressLine> </address> </contact> <contact> ... </contact> </contacts> <businessServices> <businessService serviceKey="required" businessKey="optional"> ... </businessService> </businessServices> <identifierBag> ... </identifierBag> <categoryBag> ... </categoryBag> </businessEntity> |
businessEntity
记录并不一定要很复杂。事实上,按照 businessKey
的要求,单个名称和一个唯一标识符就足够了。不过,出于完整性考虑,我包含了完整的结构,但去掉了一些稍后将另行讨论的部分。在生产环境中,应将空白元素删除。
让我们看一看此处的一些信息。
从代码的起始处开始,businessKey
当然是唯一标识符。operator 和 authorizedName
属性由注册中心内部进行处理;您不必考虑这部分内容,它们仅仅分别表示运行注册中心的实体和添加此记录的人员或帐户。
discoveryURLs
会在每次将 businessEntity 保存到注册中心时添加到注册中心。这些 URL 旨在用作供用户访问有关 businessEntity
的更多信息的地址。
请注意,Francis 添加了一个额外的名称,用于以法语表示其名称(报社打算在法国宣传其业务)。这些实体中的每一个都具有 lang
属性,用于指定相关语言的代码。您可以提供常见缩写的可替换名称,如 IBM 对应于 International Business Machines。
接下来的可选描述是一个简单的文本字符串。事实上,UDDI 中的大部分元素都具有一个可选描述。
接下来,Francis 添加了其他一些联系人。对于每个联系人,他可以根据需要指定任意多的信息。通常会提供 personName
,但电话号码、电子邮件等其他信息是由个人自行提供的,因为 UDDI 注册中心的所有信息对所有用户均可用。联系人还可能具有地址信息,使用 useType
来指定地址类型。例如,对于联系人,它可以为家庭地址和公司地址等。对于公司,useType
可以为总部、发行中心等等。
businessServices
元素将列出已与 businessEntity
关联的任何服务。由于 Gene 尚未添加任何服务,故而此元素通常为空。最后两项 identifierBag
和 categoryBag
提供了有关公司本身的其他信息,以便进行搜索。我们稍后将对二者分别进行分析。
|
|
publisherAssertion
publisherAssertion
是 businessEntity
之间的关系声明。例如,Francis 知道此项目的目标之一是使用 Daily Star 中提供的服务,其中,Daily Star 将为 Daily Moon 提供体育赛事比分。这使得 Daily Star 成为 Daily Moon 的内容提供者。Francis 可以按照清单 3 中所示的方式表示此关系。
清单 3. publisherAssertion
<publisherAssertion> <fromKey>(businessKey for Daily Star)</fromKey> <toKey>(businessKey for Daily Moon)</toKey> <keyedReference tModelKey="904BD800-D53A-11DA-B055-850A1DA99D79" keyName="optional" keyValue="CONTENTPROVIDER" /> </publisherAssertion> |
fromKey
和 toKey
元素表示所涉及的两个实体的唯一 ID。在本例中,这两个实体指 Daily Moon 和 Daily Star。Daily Star 是 Daily Moon 的内容提供者,故而据此放置二者的键。keyedReference
将会多次出现。在本例中,我们可以说引用本身就是内容提供者。keyValue
是 keyedReference
的唯一必需属性,但常常也会包含 keyName
(为了提高可读性)和 tModelKey
(标识特定的引用类型)。在本例中,tModelKey
表示两个报社之间关联的命名空间(与内部关系相对)。我们稍后将对 tModels
进行进一步的讨论。
|
|
businessService
接下来,Francis 需要输入有关 Daily Moon 将要提供的任何实际服务的信息。除了所需的唯一 serviceKey
和名称外,businessService
对象中还包含两条重要信息。即 bindingTemplates
和服务所属的任何类别。请参见清单 4。
清单 4. businessService
<businessService serviceKey="required" businessKey="optional"> <name></name> <description></description> <bindingTemplates> <bindingTemplate serviceKey="optional" bindingKey="required"> ... </bindingTemplate> </bindingTemplates> <categoryBag> ... </categoryBag> </businessService> |
|
|
BindingTemplate
Tmodelinstancedetails
指示其兼容的应用程序或规范。请参见清单 5。
清单 5. bindingTemplate
<bindingTemplate serviceKey="optional" bindingKey="required"> <accessPoint> OR <hostingRedirector bindingKey="another binding to be used instead"> <tModelInstanceDetails> <tModelInstanceDetail> <tModelInstanceInfo tModelKey=""uuid key for specification tModel">> <description></description> <instanceDetails> <description></description> <overviewDoc> <description></description> <overviewURL></overviewURL> </overviewDoc> <instanceParams>string</intstanceParms> </instanceDetails> </tModelInstanceInfo> <tModelInstanceInfo> ... </tModelInstanceInfo> </tModelInstanceDetail> <tModelInstanceDetails> </bindingTemplate> TModels (including tModel of tModels) Serve two purposes. As specification indicators, and as namespace indicators. <tModel tModelKey="required" operator="optional" authorizedName="optional"> <name></name> <description></description> <overviewDoc> <description></description> <overviewURL></overviewURL> <overviewDoc> <identifierBag> ... </identifierBag> <categoryBag> ... </categoryBag> </tModel> |
bindingTemplate
定义在何处能找到服务以及其执行什么工作,这听起来并不复杂。不过,这两项功能在 UDDI 上下文中担任了新的重要角色。例如,为了确定可以在何处访问服务,可以提供 accessPoint
(表示简单的 URL)或任何其他相应的数据,如求助热线的号码或 hostingRedirector
。
|
当服务的绑定发生更改时,将使用 hostingRedirector
。例如,如果 Daily Moon 要建立自己的分类广告服务,并允许这两家报社使用 createNewAdd()
调用提交广告,则需要确保服务永远不会更改,或者提供一个方法来告知客户机服务已发生更改。而这就是要使用 hostingRedirector
的地方。在这种情况下,Francis(或实际由 Gene 进行)将创建一个新 bindingTemplate
,用于表示新信息,并将该 bindingTemplate
的 bindingKey
输入 hostingRedirector
元素的 bindingKey
属性中。
定义服务能进行的工作可能会更困难。这个原因是两方面的。首先,由于我们讨论的并不一定是 SOAP 服务,因此无法直接为其提供 WSDL 文件。其次,由于这应该是一个自动化过程,因此需要以无歧义的方式提供此信息。
这样所得的结果是一个包括 tModelInstanceDetails
元素的 bindingTemplate
,而此元素中又包含一个或多个 tModelInstanceDetail
元素。每个 tModelInstanceDetail
元素又包含一个或多个 tModelInstanceInfo
元素,而后者各自指向一个特定的 tModel
。我们稍后将对 tModels
进行讨论。不过,重要的是要理解,tModelInstanceInfo
元素可以包含一个 instanceDetails
元素,后者本身包含一个 overviewDoc
,其中包括 overviewURL
,即实际定义服务的文档的 URL。(是的,就是在此处指定 WSDL 文件。)
|
|
TModels(包括 tModels 的 tModel)
现在让我们讨论一下 tModels
。
tModels
实际有两个用途。第一,就是我们在关于 publisherAssertions
的讨论中了解到的,作为“命名空间指示符”。也就是说,tModel
可以提供用于区分很容易混淆的信息类型的方法。经常给出的一个例子是税码(或其他很容易混淆的数字)。例如,包含以下内容的 keyedReference
并不会提供所有信息,因为这两个税务 ID 属于不同的国家。它们在两个国家里都称为税务 ID,但就编程而言,我们必须提供一个区分二者的方法,如清单 6 中所示。
清单 6. 来自不同国家的税务 ID
<keyedReference tModelKey="" keyName="taxid" keyValue="11111111" /> <keyedReference tModelKey="" keyName="taxid" keyValue="22222222" /> |
这就是要使用 tModel
的地方。我们可以为“美国税码”创建一个键模型,再为“墨西哥税码”创建一个键模型,依此类推。创建了这些模型后,可以使用其 tModel
键来进一步限定这些 keyedReference
。请参见清单 7。
清单 7. tModels 和 keyedReferences
<tModel tModelKey="902CDE50-D53A-11DA-B055-A74C17FA61A7"> <name>United States codes</name> </tModel> <tModel tModelKey="062377D0-D5F5-11DA-8170-8ACF057FECAD"> <name>Mexico codes</name> </tModel> <keyedReference tModelKey="902CDE50-D53A-11DA-B055-A74C17FA61A7" keyName="taxid" keyValue="11111111" /> <keyedReference tModelKey="062377D0-D5F5-11DA-8170-8ACF057FECAD" keyName="taxid" keyValue="22222222" /> |
tModel
的另一个用途是作为规范标识符。例如,Francis 知道 Gene 将为上个月所处理的 ClassifiedService
创建相应的条目。此服务表示特定的接口,因此可以使用 tModel
对其进行标识。tModel
可能与清单 8 中所示类似。
清单 8. tModel
<tModel tModelKey="66999A50-D5F4-11DA-9A50-FA44D6AD622A" operator="optional" authorizedName="optional"> <name>Classified Service Interface</name> <description></description> <overviewDoc> <description></description> <overviewURL> http://www.daily-moon.com/ClassifiedService-interface.wsdl </overviewURL> <overviewDoc> <identifierBag> ... </identifierBag> <categoryBag> ... </categoryBag> </tModel> |
和我们所讨论的各个其他对象一样,tModel
具有一个唯一键,这是它唯一必需的信息。不过,在本例中,我们还要指定 overviewURL
,即接口的 WSDL 文件的 URL。(我们将在后面部分创建它。)
同样,可以使用 identifierBag
对 tModels
进行标识,还可以使用 categoryBag
对其进行归类。接下来让我们看一看如何进行此工作。
|
|
identifierBag
由于 UDDI 设计十分灵活,因此没有特定的方式来标识 businessEntity。UDDI 并不强制要求使用其 D-U-N-S 编号、其税务 ID 编号或任何特定的标识方法对公司进行标识。相反,它提供了一个容器,可以根据需要在其中放置任意数量的标识符,如清单9 中所示。
清单 9. indentifierBag
<identifierBag> <keyedReference tModelKey="4064C064-6D14-4F35-8953-9652106476A9" keyName="DUNS Number" keyValue="55555555" /><keyedReference tModelKey="" keyName="US Tax ID" keyValue="111111111" /> </identifierBag> |
在 identifierBag
中添加的每个 keyedReference
都代表用户在搜索中找到相关对象的另一个机会。
|
|
categoryBag
categoryBag
的工作方式与 identifierBag
类似,因为其中包含一个或多个 keyedReferences
。请参见清单 10。
清单 10. categoryBag
<categoryBag> <keyedReference tModelKey="C0B9FE13-179F-413D-8A5B-5004DB8E5BB2" keyName="optional" keyValue="511110" /> </categoryBag> |
在本例中,Francis 创建了一个 categoryBag
,指示 Daily Moon 是一个报社分支机构。现在让我们了解如何使用所有这些对象。
|
|
将 WSDL 映射到 UDDI
在 Gene 编写任何代码将所有这些信息发送到 UDDI 注册中心前,他必须在其当前服务和 UDDI 之间建立一个重要的联系。他必须对其进行调整,以适应 UDDI 的服务、接口和绑定模板概念。
服务与接口
您可能还记得,服务在 UDDI 中包含三个部分:接口(使用 tModels
定义)、businessService
和 bindingTemplate
(用于将两者捆绑在一起)。因此,Gene 将首先确定用于定义 SOAP 服务的 WSDL 文件如何适应此结构。
他首先对 WSDL 进行分析。幸运的是,这非常简单。除了实现本身外,其余所有 WSDL 内容都属于接口。请参见清单 11。
清单 11. WSDL 接口
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://ws.apache.org/axis2" xmlns:axis2="http://ws.apache.org/axis2" xmlns:ns1="http://org.apache.axis2/xsd" targetNamespace="http://ws.apache.org/axis2"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> <xs:element type="ns1:ClassifiedAd" name="ClassifiedAd" /> <xs:complexType name="ClassifiedAd"> <xs:sequence> <xs:element type="xs:int" name="id" /> <xs:element type="xs:string" name="content" /> <xs:element type="xs:string" name="endDate" /> <xs:element type="xs:string" name="startDate" /> </xs:sequence> </xs:complexType> ... </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequestMessage"> <wsdl:part name="part1" element="ns1:createNewAdRequest" /> </wsdl:message> <wsdl:message name="createNewAdResponseMessage"> <wsdl:part name="part1" element="ns1:createNewAdResponse" /> </wsdl:message> ... <wsdl:portType name="ClassifiedServicePortType"> <wsdl:operation name="finalizeIssue"> <wsdl:input message="tns:finalizeIssueRequestMessage" /> </wsdl:operation> <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequestMessage" /> <wsdl:output message="tns:createNewAdResponseMessage" /> </wsdl:operation> ... </wsdl:portType> <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:output> </wsdl:operation> ... </wsdl:binding> </wsdl:definitions> |
这包括类型定义(XML 模式)、任何消息、portType
甚至 binding
,因为绑定并不是特定于实现的。
实现由实际的服务元素组成。请参见清单 12。
清单 12. 服务实现 WSDL
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns= "http://www.daily-moon.com/ClassifiedService-interface" xmlns:axis2="http://ws.apache.org/axis2" xmlns:ns1="http://org.apache.axis2/xsd" targetNamespace= "http://www.daily-moon.com/ClassifiedService-interface"> <wsdl:import namespace="http://ws.apache.org/axis2" location= "http://www.nicholaschase.com/ClassifiedService-interface.wsdl" /> <wsdl:service name="ClassifiedService"> <wsdl:port name="ClassifiedServicePort" binding="axis2:ClassifiedServiceBinding"> <soap:address location= "http://www.daily-moon.com:8080/axis2/services/ClassifiedService" /> </wsdl:port> </wsdl:service> </wsdl:definitions> |
请注意,实现文件导入了接口文件。也就是说,此文件是服务的完整定义。
现在让我们来看一看这如何与我们的 UDDI 对象对应。
|
|
将接口映射到 tModel
Gene 首先必须将接口映射到相应的 tModel
。请参见清单 13。
清单 13. tModel
<tModel tModelKey="66999A50-D5F4-11DA-9A50-FA44D6AD622A"> <name>http://www.daily-moon.com/ClassifiedService- interface</name> <description>Interface for the Daily Moon Classified Department web application</description> <overviewDoc> <description>WSDL interface document</description> <overviewURL> http://www.daily-moon.com/ClassifiedService-interface.wsdl </overviewURL> <overviewDoc> <categoryBag> <keyedReference tModelKey="C1ACF26D-9672-4404-9D70-39B756E62AB4" keyName="uddi-org:types" keyValue="wsdlSpec" /> <keyedReference tModelKey="C0B9FE13-179F-413D-8A5B-5004DB8E5BB2" keyName="ntis-gov:naics:1997" keyValue="511110" /> </categoryBag> </tModel> |
首先看最下面,请注意 categoryBag
。Gene 添加了两个 keyReferences
。第一个指定我们事实上在处理 WSDL 文件。已预定义了特定的 tModelKey
来表示 uddi-org:types
命名空间。所有 WSDL 文件都必须采用这种方式指定。第二个引用绑定到 ntis-gov:naics:1997
命名空间,因此 Gene 的用户可以方便地在表示与报纸有关的服务的所有 WSDL 文件中找到此定义。继续往上,我们可以看到 overviewDoc
。除了可选描述外,它还指定了实际的 URL,可以在此处找到 WSDL 文件。
最后,tModel
的名称应与 WSDL 文件的目标命名空间匹配。
|
|
将实现映射到绑定模板
Gene 接下来必须将实现本身映射到 bindingTemplate
。请参见清单 14。
清单 14. bindingTemplate
<bindingTemplate serviceKey="" bindingKey=""> <accessPoint> http://www.daily-moon.com:8080/axis2/services/ClassifiedService </accessPoint> <tModelInstanceDetails> <tModelInstanceDetail> <tModelInstanceInfo tModelKey="66999A50-D5F4-11DA-9A50-FA44D6AD622A"> <instanceDetails> <description>The canonical implementation of the Daily Moon's classified service.</description> <overviewDoc> <overviewURL> http://www.daily-moon.com/ClassifiedService-impl.wsdl </overviewURL> </overviewDoc> </instanceDetails> </tModelInstanceInfo> </tModelInstanceDetail> </tModelInstanceDetails> </bindingTemplate> |
这里我们看到,Gene 创建了一个新 bindingTemplate
,并将 accessPoint
设置为实际服务的 URL。键 modelInstanceDetails
将接口 tModel
(通过 tModelKey
)链接到实现文档(在 overviewDoc
中指定)。现在他只需要从服务引用它即可。
|
|
从 businessService 和 businessEntity 引用 bindingTemplate
最后一步是将所有这些组装起来,并从 businessService
引用 bindingTemplate
、从 businessEntity
引用 businessService
。请参见清单 15。
清单 15. 完整的 businessEntity
<businessEntity businessKey="1A3DB880-D5F4-11DA-B880-F94D3591C691"> <name>The Daily Moon</name> <name lang="fr-ca">La Lune Quotidienne</name> <contacts> <contact> <personName>Pat Mooney</personName> <email>[email protected]</email> </contact> </contacts> <businessServices> <businessService serviceKey="064B4170-D5F5-11DA-8170-A74C17FA61A7"> <name>ClassifiedService</name> <bindingTemplates> <bindingTemplate bindingKey="904BD800-D53A-11DA-B055-850A1DA99D79"> <accessPoint> http://www.daily-moon.com:8080/axis2/services/ClassifiedService </accessPoint> <tModelInstanceDetails> <tModelInstanceDetail> <tModelInstanceInfo tModelKey="66999A50-D5F4-11DA-9A50-FA44D6AD622A"> <instanceDetails> <description>The canonical implementation of the Daily Moon's classified service.</description> <overviewDoc> <overviewURL> http://www.daily-moon.com/ClassifiedService-impl.wsdl </overviewURL> </overviewDoc> </instanceDetails> </tModelInstanceInfo> </tModelInstanceDetail> </tModelInstanceDetails> </bindingTemplate> </bindingTemplates> <categoryBag> <keyedReference tModelKey="C1ACF26D-9672-4404-9D70-39B756E62AB4" keyName="uddi-org:types" keyValue="wsdlSpec" /> <keyedReference tModelKey="C0B9FE13-179F-413D-8A5B-5004DB8E5BB2" keyName="ntis-gov:naics:1997" keyValue="511110" /> </categoryBag> </businessService> </businessServices> <identifierBag> <keyedReference tModelKey="4064C064-6D14-4F35-8953-9652106476A9" keyName="DUNS Number" keyValue="55555555" /> <keyedReference tModelKey="" keyName="US Tax ID" keyValue="111111111" /> </identifierBag> <categoryBag> <keyedReference tModelKey="C0B9FE13-179F-413D-8A5B-5004DB8E5BB2" keyName="optional" keyValue="511110" /> </categoryBag> </businessEntity> |
也就是说,服务现在已经完成:Gene 现在有了一个包含服务的 businessEntity
。
|
|