【编辑注:本文所描述的 IBM Lotus Domino V8 特性和更新针对的是 Beta 版软件。本文及其屏幕截图可能并不反映最终推出的产品的功能。】
本文演示了为 Lotus Domino V8 开发 Web 服务,同时保持与 Lotus Domino V7.0.2 的向后兼容性。文中使用的 示例 是一组针对 Discussion 数据库模板的 Web 服务。这个解决方案作为 IBM 都柏林软件实验室时下进行的 Service-Oriented Architecture (SOA) Growth Project 计划的一部分,其目的是通过为 IBM 产品增加一些技术启用程序便于在 SOA 中进行集成,从而使基于 SOA 的解决方案得到更好的采用。这个特殊的解决方案有两个主要目标:
Discussion 数据库模板由于使用广泛,因此通常被选作一种代表性工具将它的一些功能公开为 Web 服务。通过 discussion 模板创建的数据库允许多个用户创建、删除和修改主题,响应主题以及对响应作出响应。另外,这些主题和响应可以是公有的,也可以是私有的,并且允许根据数据库中的视图对它们进行过滤。 每个作者都可以创建、修改和删除自己的配置文件,而一些有特权的作者还可以阅读其他人的配置文件。
构建该解决方案的目的是公开以下三种逻辑 Web 服务:
使用 LotusScript 来实现该解决方案的原因在于:它是一种成熟的技术并且在 Lotus Domino 开发社区中使用广泛。WS-I 的互操作性是使用 Basic Profile 1.1 的 WS-I Interoperability Testing Tool 来验证的。
本文总结了开发这个解决方案的经验并讨论了使用 Lotus Domino V8 开发自己的 Web 服务的最佳实践。本文还强调了实现 Lotus Domino V8 的 WS-I 的依从性的几个陷阱和应对措施,以及与 Lotus Domino V7.0.2 兼容的问题。Lotus Domino V7.0.2 兼容性是一个主要的需求,因为企业可能要花些时间才能迁移到 Lotus Domino V8。
本节将对 Domino Discussion 数据库 Web 服务应用程序中使用的架构进行概述。重点介绍 Lotus Domino 中约束设计选择的一些限制;描述公开的接口并介绍如何实现 Lotus Domino V7.0.2 和 V8 之间的兼容性。
Discussion 数据库 Web 服务是作为无状态 Web 服务进行设计的。在某些情形下,有状态 Web 服务更加适当,例如,提供分页机制以列出数据库中的主题和响应。 有状态的 Web 服务在集群的 Lotus Domino 环境下不能进行故障恢复,因为 Lotus Domino 没有提供在节点间异步复制会话和状态的功能。出于这个原因和简单性的考虑,我们选择实现无状态的 Web 服务。
Discussion 数据库 Web 服务在功能上可以分解为三种不同的服务。
Web 服务的 LIST 方法返回主题、响应、作者、视图名和文件夹名的列表。这些方法提供了多个备选方案以允许将返回的列表根据排序标准进行排序。返回的列表可以根据 Notes Formula 语言查询、示例查询或视图进行过滤。一些提供简单分页机制的列表方法是无状态的。要使用这些方法,用户必须提供页号和所需的元素号。每次调用时收集文档;因此根据假设,如果数据库在两个调用之间发生变化,则两个不同的页面中可能返回相同的元素。
数据传输对象(data transfer objects,DTOs)或值类型如 Lotus Domino Web 服务文档中介绍的那样,是用于在 Web 服务和客户机之间交换数据的自定义类。
对于 Discussion 数据库,我们拥有以下一些 DTOs,如图 1 所示:
Web 服务抛出一些自定义错误,其中的字段指定了以下内容:
错误可以分类为以下几组:
Web 服务的设计目的是对 Lotus Domino V7.0.2 和 Lotus Domino V8 使用相同的接口,同时实现使用一个替代方案来完成本文 “实现” 一节所描述的源代码可移植性。
在本节中,我们将描述 Web 服务实现和在跨 Lotus Domino V7.0.2 和 Lotus Domino V8 实现这些服务时所发现的问题。我们将描述如何使用开发环境提供 LotusScript 实现的跨版本兼容性,如何处理传递给 Web 服务的 LotusScript 数组、null 和复杂数据类型,如何处理错误,以及如何复制 Lotus Notes 中的相同行为来保证 Web 服务的安全。 我们使用 Java 1.4、Axis 1.4 和 Junit 3.8 来创建测试实现的测试套件。 使用 Ant 和 Cruisecontrol 可以连续地编译和运行测试套件。
Lotus Domino V8 拥有的 Web 服务引擎比 Lotus Domino V7.0.2 的高级,因此不能使用 IBM Lotus Domino Designer V8 来创建 Lotus Domino V7.0.2 上运行的 Web 服务。使用 Web 浏览器访问 Lotus Domino V7.0.2 服务器中运行的 Lotus Domino Designer V8 Web 服务时会显示以下错误。
"This version of the Web Service design is not supported on this server"
Lotus Domino Designer V7.0.2 Web 服务在 Lotus Domino V8 服务器中运行良好。同样道理,使用 Lotus Domino Designer V8 创建或编辑的 Web 服务不能使用 Lotus Domino Designer V7.0.2 或更低的版本来编辑。当您在 Lotus Domino Designer V7.0.2 中打开 Lotus Domino V8 Web 服务时就会出现图 2 所示的警告:
Discussion 数据库 Web 服务提供的列表方法返回数据传输对象数组。LotusScript 没有提供在函数中返回数组的功能。数组通常是使用 LotusScript 中的 Variant 对象来返回,但是对于 Web 服务,Variant 没有提供足够的信息便于 WSDL 生成。为了帮助正常地生成 WSDL,我们使用一个 holder 类。holder 类是一个派生自 INOUT_HOLDER 类的 LotusScript 类对象(如 lsxsd.lss 中定义的那样)。生成的 WSDL 删除 holder 类。如预期那样,客户端使用 Web 服务时只看见一个返回的数组。developerWorks 文章 “Practical Web services in IBM Lotus Domino 7: Writing and testing simple Web services” 和 “Lotus Notes/Domino 7 Web Services” 对如何在 LotusScript Web 服务方法中使用数组 holder 类返回数组作出了更详细的解释。
注意:lsxsd.lss 库中包含的类允许您传递字符串数组、文件和日期。在本地的 Notes 程序目录下可以找到此文件。
清单 1 和清单 2 展示了一个 holder 类示例及其生成的 WSDL 部分(展示 AuthorDTO 数组)。
Class AuthorDTOArray_Holder as INOUT_HOLDER'The AuthorDTO array holder classPublic value() As AuthorDTO......End Class |
<complexType name="AUTHORDTOArray"> <sequence> <element maxOccurs="unbounded" minOccurs="0" name="item" type="impl:AUTHORDTO"/> </sequence></complexType> |
不幸的是,没有说明如何将数组作为参数传递给 LotusScript Web 服务方法。 在开发 Discussion 数据库 Web 服务期间,我们尝试了两种不同的方法,直接传递数组(清单 3)以及对原语类型和复杂类型使用 holder 类(清单 4)。
Sub markListRead(ids() As String)...End SubSub markTopicsRead(topics() as TopicDTO)...End Sub |
Sub markListUnread(ids As STRINGARRAY_HOLDER)...End SubSub markTopicsUnread(topics As TopicDTOArray_Holder)...End Sub |
这两种方法在 Lotus Domino V8 中都有效。这些工作在 Lotus Domino V7.0.2 中使用 RPC Encoded WSDL 来完成。我们不使用 RPC 编码因为它不受 WS-I Basic Profile 1.1 支持。在默认情况下,这些方法在使用其他编码的 Lotus Domino V7.0.2 中无效。 当数组或数组 holders 用于原语类型时,Web 服务方法从基于 Axis 的测试客户机接收空数组。当数组或数组 holders 用于复杂类型时,Web 服务错误被返回到包含清单 5 所示错误消息的客户机。
“Web service (DiscussionThreadManager) object does not have specified member TOPICS in method MARKTOPICSREAD: value "" at element quot;urn:DefaultNamespace:MARKTOPICSREAD/TOPICS"” |
可以通过手工编辑 WSDL(从清单 6 到清单 7)使数组生效。
<complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent></complexType> |
<complexType name="ArrayOf_xsd_string"> <sequence> <element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:string"/> </sequence></complexType> |
这个问题的应对方法是使用一个用作数组容器但是没有扩展 INOUT_HOLDER 的自定义类。在 Lotus Domino V8 中,任何包含数组字段的自定义类都被自动视为数组 holder。为了避免这种行为并创建一致的接口 —— 即不管 LotusScript 部署在 Lotus Domino V7.0.2 或 Lotus Domino V8 Beta 上都可以通用接口,可以使用包含多个字段的自定义类,如清单 8 所示。
Class IDList Public ids() As String Public type As StringEnd Class |
LotusScript 原生数据类型(如 String、Integer 或 Boolean)不允许使用 null 值。要使用 null 值,比如,要为主题 DTO 中的 body 字段传递一个 null 值,我们使用 lsxsd.lss 库中的数据类型(如 XSD_String 或 XSD_Boolean),这些类型允许使用 null 值。清单 9 展示了带有 XSD_String 类型字段的 TopicDTO 类,清单 10 中生成的 WSDL 的相应部分显示,body 属性可以为空。
Class TopicDTO Public body As XSD_STRING ...End Class |
<complexType name="TOPICDTO"> <sequence> <element name="BODY" nillable="true" type="xsd:string"/>...... </sequence></complexType> |
当带有复杂类型参数的 Web 服务方法收到 null 或带 null 值属性的实例时,Lotus Domino V7.0.2 和 Lotus Domino V8 的行为不尽相同。Lotus Domino V8 将 null 视为 LotusScript Nothing(即其他编程语言中的 null),而 Lotus Domino V7.0.2 则使用默认值对它们进行实例化。数值字段被赋以 0 值,而字符串字段则赋以空字符串值。类的实例化是给它们所有的原语类型属性赋予默认值。这个行为在 Lotus Domino V7.0.2 和 Lotus Domino V8 中需要使用不同的方法来进行 null 检查。
清单 11 中的代码首先检查传递的响应是否为 null,如果不是,则检查所需字段是否为 null。
Function createResponse(response As ResponseDTO) As ResponseDTO If response Is Nothing Then Error 1, "Response is null." End If If response.parentID Is Nothing Then Error 1, "The Responses parent ID is null." End If ...End Function |
这段代码在 Lotus Domino V8 中运行正常,但在 Lotus Domino V7.0.2 中响应实例决不是 Nothing,因为它已被实例化为默认值。如果已传递响应,则 parentID 决不是 Nothing,原因同上。
Function createResponse(response As ResponseDTO) As ResponseDTO If response.ID Is Nothing Then Error 1, "Response is null." End If If response.parentID.GetValueAsString = "" Then Error 1, "The Responses parent ID is null." End If ...End Function |
在 Lotus Domino V7.0.2 中,清单 12 中的代码可以正常运行,原因在于收到的输入是 null 参数时将动态地进行对象实例化。在 Lotus Domino V8 中,null 参数在 LotusScript 中会变成 Nothing,因此如果 response 是 Nothing 则 response.ID 将导致错误,而如果 parentID 字段是 Nothing 则 response.parentID.GetValueAsString 将导致错误。
一种创建在 Lotus Domino V7.0.2 和 Lotus Domino V8 中都能运行的代码的应变方案需要使用一条 If 语句来根据 LotusScript 版本对代码进行分支。当开发从 Versioon 8 向后兼容到 Version V7.0.2 的 Web 服务时,我们需要一种方法来确定在哪个版本上运行 Web 服务。使用清单 13 所示的 Getthreadinfo() 函数可以找到这条信息。通过使用一条 If 语句,Getthreadinfo(LSI_THREAD_VERSION) 函数可以返回 Lotus Domino V7.0.2 的 LotusScript 版本,即 5.0.0.07B。Lotus Domino V7.0.2 执行 If 分支中的代码,而更高版本则执行 Else 分支中的代码。
Function createResponse(response As ResponseDTO) As ResponseDTO If CStr(GetThreadInfo(LSI_THREAD_VERSION)) <= "5.0.0.07B" Then ' Domino 7.0.2 or earlier If response.ID Is Nothing Then Error 1, "Response is null." End If If response.parentID.GetValueAsString = "" Then Error 1, "The Responses parent ID is null." End If Else ' Later than Domino 7.0.2 If response Is Nothing Then Error 1, "Response is null." End If If response.parentID Is Nothing Then Error 1, "The Responses parent ID is null." End If End IF ...End Function |
我们将在此介绍 LotusScript 如何处理错误以及如何利用它使 Web 服务错误能够给客户机提供一些有用的信息。LotusScript 提供了三个函数来考察当前错误的状态并显示错误信息。这些函数分别是:
在 LotusScript 中通过使用一个特殊的出口参数来抛出 Web 服务错误,该参数是 WS_Fault 类(可从 lsxsd.lss 库中获得)的实例,如 developerWorks 文章 “在 IBM Lotus Domino 7 中使用 Web 服务,第 3 部分: 编写复杂的 Web 服务” 所示。 见清单 14。
Function foo(fault As WS_FAULT) As ... Fault.SetFault True Fault.setFaultString "error message" End Function |
Lotus Domino V8 处理的自定义错误是 WS_Fault 类的扩展。它使 Axis 1.4 能够将错误生成为 AxisFault 的子类,当发生错误时将捕获到这些子类。清单 15 中的代码使用 OnError 语句来捕获运行时错误并使用自定义的 throwFault 函数来实例化 DiscussionError。DiscussionError 是一个(默认)自定义类,其中包含了错误消息、生成消息的函数名和包含 Web 服务的数据库名。函数名通过 GetThreadIfo(LSI_THREAD_PROC) 函数来收集。出于适用性考虑,错误在生成时被使用 nLog.logError 函数记录到日志数据库。
Function createTopic(topic As TopicDTO, fault As DiscussionError) As TopicDTO On Error Goto FAULT ... Exit FunctionFAULT: Set fault = throwFault(fault, GetThreadInfo(LSI_THREAD_PROC), database.FileName) nLog.LogError Err, "Error in " & GetThreadInfo(LSI_THREAD_PROC) & " : " & Error & " Line : " & Erl Exit FunctionEnd Function |
Lotus Domino V7.0.2 没有返回 SOAP 错误子类型成员数据。结果,不管在 Lotus Domino V7.0.2 中使用的自定义类是什么,所有的错误在运行时都被客户机视为 AxisFault 异常而不是自定义错误。例如,Axis 1.4 生成了一个自定义异常类,但是 Web 服务在运行时决不会抛出该异常。我们尚未找到此问题的解决方法。
Web 服务提供的用户访问权限与 Lotus Notes 客户机施加的权限一致。在 Lotus Domino 中,每个文档都有一个 Authors 字段和一个 Readers 字段;请参阅 Lotus Domino Designer 文档。Authors 字段决定了谁能够编辑或更新文档。Readers 字段控制谁能够阅读文档。为达到 Lotus Notes 客户机和 Web 服务之间的一致性,当创建一个主题或响应的时候,用户被添加到 Authors 字段。如果用户选择将主题或响应设为私有,则用户被添加到 Readers 字段。主题和响应有一个 Boolean 字段可将它们标记为私有或公有。
在本节中,我们将描述如何配置 Lotus Domino 来公开安全 Web 服务并部署这些服务。 在本例中,我们将展示如何部署为 Discussion 数据库开发的 DiscussionProfileManager Web 服务。 您可以按照同样的步骤部署针对此解决方案开发的另外两个 Web 服务:DiscussionThreadManager 和 DiscussionViewManager。
为使用户能够以一种安全的方式访问 Web 服务,Lotus Domino 应使用带有 HTTPS 协议的嵌入式 Web 服务器。
要配置服务器,应执行以下操作:
要部署此 Web 服务,请按照以下步骤执行:
现在可用以下地址获得 Web 服务:
http://<DominoServer>/<Database Path>/DiscussionProfileManager
注意:根据默认,Web 服务引擎被配置为单线程引擎。要更改此默认配置,需要使用 Lotus Domino Administrator 客户机连接到服务器,选择左侧窗格上的 Server 图标,打开列表,选择 Current Server Document,转到 Internet Protocols 附签,单击 Domino Web Engine 附签,然后将 Web Agents 设置 “Run Web agents concurrently?” 条目从 Disabled 改为 Enabled,如图 7 所示。然后执行 HTTP 任务重新启动或重新启动服务器。
关于咨询 IBM Redpaper 的更多详细信息,请参阅 “IBM Lotus Domino for iSeries, performance, and tuning”。
WS-I 依从性的目标是保证 Discussion 数据库 Web 服务之间的互操作性,允许客户机通过其他支持 Web 服务的技术来使用这些服务。例如,J2ME 客户机要求所有的 Web Service Description Language (WSDL) 定义都满足 WS-I 依从性。
Web Services Interoperability Organisation 开发了一个测试工具,用来评估 Web 服务对 Basic Profile 1.1 的依从性。此工具使用一个非侵入式的黑盒方法来测试 Web 服务实现。该工具的测试重点在于 Web 服务和用户应用程序之间的交互。 要执行这些测试,我们可以使用 Interoperability Testing Tool 1.1。
该测试工具包含一个 Monitor、一个 Analyzer(见图 8)和各种支持文件。Monitor 用作消息捕获和日志记录的工具。它将截取消息而记录器对这些消息重新定义格式并将它们存储到一个消息日志中以便以后进行分析。Monitor 使用中间方法中的 man 截取和记录消息来实现。Analyzer 是一个分析工具,用来验证 Web 服务对 WS-I Profiles 的依从性。它将分析发送到 Web 服务的消息和从 Web 服务发出的消息,前提是 Monitor 已经将这些消息记录到消息日志中。
有关更多的详细信息,请参阅 WS-I Organization 中的参考资料,使 Web 服务开发人员能够创建互操作的 Web 服务并验证其结果是否符合 WS-I 指南。
工具中附带了关于 Interoperability Test Tool 的使用方法的说明。
Lotus Domino 允许使用以下编码发布 Web 服务:
RPC-encoded Web 服务不受 WS-I Basic Profile 1.1 支持,因此,本文不再对它进行讨论。在 Web 服务开发期间,对于其他三种编码 Document Wrapped、Document Literal 和 RPC Literal,我们针对 Lotus Domino V7.0.2 和 Lotus Domino V8 都执行了静态和动态 WS-I 依从性测试。
静态测试指使用 Analyzer 对每个 Web 服务 WSDL 执行静态分析。 动态测试指使用 Monitor 记录 Web 服务和客户机之间的 SOAP 消息;在本例中,客户机一个基于 Axis 1.4 的 JUnit Test Suite。Monitor 将 SOAP 消息记录到一个日志文件中,Analyzer 工具稍后将分析这个日志文件。生成的依从性报告文件指明 Web 服务是否满足 WS-I 依从性。
Lotus Domino V7.0.2 和 V8 WS-I 失败
Lotus Domino V7.0.2 生成的 WSDL 在以下情形下会使 WS-I Interoperability Tests 失败:
Lotus Domino V8 生成的 WSDL 在以下情形会使 WS-I Interoperability Tests 失败:
这里通过一些错误的 WSDL 示例对这些 WS-I 失败作出了详细解释,并说明了使其满足 WSDL 依从性所需进行的更改。如 Lotus Domino Designer 文档 中所述,有些 WSDL 或 XML 模式结构对到 LotusScript 或 Java 的映射只提供了有限的支持或者不支持。当它们尝试导入 WSDL 时得不到 Lotus Domino Designer 的支持。
Lotus Domino V7.0.2 生成的用于 Web 服务的 WSDL 所包含的数组不满足 WS-I 依从性。这将对以下的编码产生影响:
WS-I 测试失败源于以下错误:
"An Array declaration uses - restricts or extends - the soapenc:Array type,
or the wsdl:arrayType attribute is used in the type declaration."
对于三种不同的编码,WSDL 中使用清单 16 所示的代码来表示数组。
<complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent></complexType> |
解决此问题的办法是手工编辑 WSDL 并将它们导入 Lotus Domino Designer 中(有关将 WSDL 导入 Lotus Domino Designer 的更多信息,请参阅 “导入 WSDL” 一节)。 要使它满足 WS-I 依从性,可删除 <complexContent> 标记并将其替换为 <sequence> 标记,如清单 17 所示。
<complexType name="ArrayOf_xsd_string"> <sequence> <element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:string"/> </sequence></complexType> |
出于 WS-I 依从性考虑,namespace 属性不能包含在任何 soapbind:body、soapbind:header、soapbind:headerfault、soapbind:fault 元素中。此问题会影响以下的 WSDL 编码:
运行 WS-I 测试工具后将得到以下错误消息:
"A document-literal binding in a DESCRIPTION MUST NOT have
the namespace attribute specified on contained soapbind:body,soapbind:header, soapbind:headerfault
and soapbind:fault elements."
清单 18 展示了生成的 WSDL 的一部分,它对于 Document Wrapped 和 Document Literal 都不满足 WS-I 依从性,二者包含了 namespace 属性。
<wsdl:binding name="DiscussionProfileManagerSoapBinding" type="impl:DiscussionProfileManagerPort"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="GETVERSION"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="GETVERSIONRequest"> <wsdlsoap:body namespace="urn:DefaultNamespace" use="literal" /> </wsdl:input> <wsdl:output name="GETVERSIONResponse"> <wsdlsoap:body namespace="urn:DefaultNamespace" use="literal" /> </wsdl:output> </wsdl:operation> |
要解决这个问题,可以手工编辑 WSDL 并从 <wsdlsoap:body> 标记删除 namespace 属性,如清单 19 中的 WSDL 示例所示。然后将 WSDL 导入到 Lotus Domino Designer 中。
<wsdl:binding name="DiscussionProfileManagerSoapBinding" type="impl:DiscussionProfileManagerPort"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="GETVERSION"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="GETVERSIONRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="GETVERSIONResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> |
当 <wsdl:message> 标记中的 <wsdl:part> 标记使用题头或错误元素的类型属性来定义时就会出现这个错误。此错误将影响以下编码:
针对此错误给出的消息是:
"A wsdl:binding in a DESCRIPTION MUST refer, in each of itssoapbind:header,
soapbind:headerfault and soapbind:fault elements, only to wsdl:part element(s) that have been defined
using the element attribute."
因为 fault 和 header 不包含参数,所以对于每个 WSDL 1.1,soapbind:fault、soapbind:header 和 soapbind:headerfault 假定 style 属性的值为 document。所有 style 属性值为 document 并且被绑定到 soapbind:body 上的 wsdl:part 元素都使用 element 属性来定义。对 soapbind:fault、soapbind:header 和 soapbind:headerfault 元素也有同样的要求。
注意:RPC Literal Web 服务的 header 元素和 fault 元素都应按 Document Literal 中相同的样式来定义,按照断言需求 R2205 编码。
清单 20 中给出了一个不满足 WS-I 依从性的 WSDL。请注意 <wsdl:part> 标记中 type 属性的使用。
<complexType name="DISCUSSIONERROR"> <sequence> ... ... </sequence></complexType>......<wsdl:message name="DISCUSSIONERROR"> <wsdl:part name="DISCUSSIONERROR" type="impl:DISCUSSIONERROR" /></wsdl:message> |
要更改这个 WSDL,使它满足 WS-I 依从性,可以手工地将 <element> 标记添加到 <complexType> 标记两侧并将 <wsdl:part> 标记中的 type 属性更改为 element 属性。清单 21 给出了一个满足依从性 WSDL 的示例。编辑 WSDL 后,将编辑后的 WSDL 导入到 Lotus Domino Designer 中。
<element name="DISCUSSIONERROR"> <complexType> <sequence> ... ... </sequence> </complexType></element>......<wsdl:message name="DISCUSSIONERROR"> <wsdl:part name="DISCUSSIONERROR" element="impl:DISCUSSIONERROR" /></wsdl:message> |
如果对于以下编码,在 <wsdl:message> 标记中有多个 <wsdl:part> 元素就会出现这个错误:
这些编码使 WS-I 测试失败后得到以下错误信息:
"A document-literal binding which does not specify the parts attribute, has more than one wsdl:part in the associated wsdl:message element."
清单 22 给出了生成的 WSDL 中出问题的部分。
<wsdl:message name="LISTAUTHORSBYEXAMPLEANDSORTCRITERIARequest"> <wsdl:part element="impl:EXAMPLE" name="EXAMPLE" /> <wsdl:part element="impl:SORT" name="SORT" /></wsdl:message> |
当定义 document/literal 服务时,在输入消息和输出消息中都最多只能有一个 body 部分。因此,Web 服务传递给方法的参数不能多于一个。如果要使用带有多个参数的方法,则必须使 Document Wrapped 编码满足依从性。
出现此错误是因为 message 元素包含了不惟一的部分。这个错误会影响以下编码:
运行 WS-I 测试后将出现以下错误消息:
"A binding has operations that are not unique."
清单 23 给出了不满足依从性的 WSDL 的一段。注意 message 元素中的一些 part 元素不惟一,比如 ID 元素就不惟一。
......<wsdl:types> <schema targetNamespace="urn:DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema"><element name="ID" type="xsd:string" /><element name="AUTHOR" type="impl:AUTHORDTO" />......</schema> </wsdl:types><wsdl:message name="GETVERSIONRequest"> Part element missing </wsdl:message><wsdl:message name="DELETEAUTHORPROFILERequest"> <wsdl:part element="intf:ID" name="ID" /> </wsdl:message><wsdl:message name="READAUTHORPROFILERequest"> <wsdl:part element="intf:ID" name="ID" /> </wsdl:message><wsdl:message name="EXISTSAUTHORPROFILERequest"> <wsdl:part element="intf:ID" name="ID" /> </wsdl:message><wsdl:message name="UPDATEAUTHORPROFILERequest"> <wsdl:part element="intf:AUTHOR" name="AUTHOR" /> </wsdl:message><wsdl:message name="CREATEAUTHORPROFILERequest"> <wsdl:part element="intf:AUTHOR" name="AUTHOR" /></wsdl:message>...... |
要满足 WS-I Basic Profile 1.1,所有的 message 元素都必须包含惟一的 part。清单 24 给出了相应的满足依从性的 WSDL 部分。注意 <wsdl:part> 标记中的元素声明和元素名现在都是惟一的。如果 Web 服务中有很多方法,那么这种解决方案可能就很麻烦。我们建议您使用 Document Wrapped 编码。阅读 Anne Thomas Manes 撰写的文章 “"The wrapped document/literal convention”。
<wsdl:types> <schema targetNamespace="urn:DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="GETVERSIONReturn" type="xsd:string" /><element name="ID_1" type="xsd:string" /><element name="ID_2" type="xsd:string" /><element name="ID_3" type="xsd:string" />...<element name="AUTHOR_1" type="impl:AUTHORDTO" /><element name="AUTHOR_2" type="impl:AUTHORDTO" />......<wsdl:message name="GETVERSIONRequest"> There must be one part element here </wsdl:message><wsdl:message name="DELETEAUTHORPROFILERequest"> <wsdl:part element="intf:ID_1" name="ID" /> </wsdl:message><wsdl:message name="EXISTSAUTHORPROFILERequest"> <wsdl:part element="intf:ID_2" name="ID" /> </wsdl:message><wsdl:message name="READAUTHORPROFILERequest"> <wsdl:part element="intf:ID_3" name="ID" /> </wsdl:message><wsdl:message name="UPDATEAUTHORPROFILERequest"> <wsdl:part element="intf:AUTHOR_1" name="AUTHOR" /> </wsdl:message><wsdl:message name="CREATEAUTHORPROFILERequest"> <wsdl:part element="intf:AUTHOR_2" name="AUTHOR" /></wsdl:message>...... |
在 Lotus Domino Designer 中,创建 Web 服务可以通过两种方法:输入代码并让 Lotus Domino Designer 生成 WSDL,或导入 WSDL 并让 Lotus Domino Designer 为 Web 服务接口生成代码签名。本文中描述的 Web 服务通过 Lotus Domino Designer 来生成 WSDL。有时使用现有的 WSDL 更好,比如,对 Lotus Domino Designer 生成的 WSDL 进行更改,使它们满足 WS-I 规范。
要通过导入 WSDL 创建 Web 服务,请执行以下步骤:
这就为 Web 服务生成了 LotusScript 函数签名。如果生成的接口被修改并保存了 Web 服务,则 Lotus Domino Designer 将使用自己自动生成的 WSDL 重写导入的 WSDL。 为防止发生这种情况并保持导入的 WSDL,在继续进行 Web 服务实现之前执行以下步骤非常重要:
WS-I 静态依从性测试可以轻松地集成到基于 Ant 的构建环境中,并通过构建自动化工具(如 CruiseControl)自动执行。我们建议您在构建解决方案时连续地检查公开的 Web 服务是否兼容。
对于 Domino Discussion 数据库 Web 服务,Lotus Domino V7.0.2 没有生成满足 WS-I 规范的 WSDL 文档,但是可以手工编辑 WSDL 文档来实现 WS-I 依从性然后将其导入 Lotus Domino Designer 中。对于 Lotus Domino V8,惟一不会使生成满足 WS-I 规范的 WSDL 文档失败的编码是 Document Wrapped 编码。所有其他的编码都必须通过手工编辑来满足 WS-I 规范。
大致说来,Lotus Domino V7.0.2 只有在使用 RPC Literal 编码并且没有使用数组和错误时才能生成满足依从性的 WSDL。Lotus Domino V8 生成满足依从性的 WSDL 的条件包括:若使用 RPC literal 编码则要求没有使用错误;若使用 Document Literal 编码则要求所有的方法都只有一个参数并且所有方法的参数都具有惟一的名称;使用 Document Wrapped 编码。
在本文中,我们介绍了如何为 Lotus Domino V8 设计 Web 服务。我们以 Discussion 数据库为例,描述了 Web 服务架构,如何分解它们的功能,如何在 Web 服务和客户机之间传输数据,而且我们还定义了可能出现的错误。我们简要地介绍了如何实现 Web 服务,如何实现与 Lotus Domino V7.0.2 兼容,可能遇到的一些问题及其解决方法。我们提出了如何配置 Lotus Domino 以便通过 HTTPS 实现安全连接,以及用户如何使用与 Notes 客户机相同的用户权限进行身份验证以便访问 Web 服务。然后我们描述了如何使用 Lotus Domino Designer 在 Domino 数据库中部署 Web 服务。
我们执行了 WS-I 互操作性测试并重点介绍了使用 Discussion 数据库的 Web 服务应使用 Document Wrapped 编码来公开。这是当 Lotus Domino 生成 WSDL 时通过 Lotus Domino V8 依从性测试的惟一编码。我们利用 Lotus Domino V7 发布的 Web 服务不能通过互操作性测试,不管生成的 WSDL 的编码是什么。满足 WS-I 规范的 WSDL 文档可以通过手工编辑 WSDL,然后将其导入 Lotus Domino Designer 中来进行创建。
用作本文示例的 Discussion 数据库 Web 服务可在 in the Lotus Sandbox 找到。
我在此要特别感谢 Gordon Hegfield、Steve Nikopoulos 和 John Grosjean 为本文所做的技术评论。
Massimiliano Parlione 是位于爱尔兰的 IBM 都柏林软件实验室的一名高级软件工程师。自 2006 年 10 月起他一直在 IBM 工作。他在 1995 年 7 月从拉奎拉大学获得计算机科学专业(本科)荣誉学士学位,并在 2000 年 4 月从罗马 La Sapienza 大学获得计算机工程专业博士学位。在加入 IBM 爱尔兰公司之前,Parlione 博士曾先后担任意大利热那亚的 Herzum 软件公司的高级顾问、IBM 罗马 Tivoli 实验室的软件工程师(研究领域为性能和可用性)、Marche 地区 IT 部门的执行官(指导地区健康服务项目),以及意大利罗马的 Italian Research Council (CNR) 和 Avezzano 的 Texas Instruments 的承包人。作为一名顾问,他一直从事各种业务的纵向联合工作,包括政府组织(意大利 Bozen 自治省)、药物批发(意大利和英国的 Alliance Boots 公司),以及产品开发公司(美国的 Infogix 和 Aspect)。他跟人合著了 IBM 红皮书 "Introducing IBM Tivoli Monitoring for Web Infrastructure" 和 "IBM Tivoli Monitoring Version 5.1.1 Creating Resource Models and Providers"。 |
David Mills 是 IBM 爱尔兰公司的一名软件工程师。他曾在爱尔兰的 University College Cork 攻读计算机科学并于 2006 年获得荣誉理学学士学位。他在 2006 年 6 月加入 IBM 的 Extreme Blue 项目。作为 Extreme Blue 的一员,他与另外三名毕业生从事改进的 IP 电话项目工作,该项目在法国的精品博览会上得到了展示。他目前是爱尔兰都柏林的 SOA 团队的一员。 |
Stephen Mc Nena 是 IBM 爱尔兰公司的一名软件工程师。他曾在爱尔兰的高威梅奥理工学院攻读软件开发并于 2004 年获得软件开发专业大专文凭,2005 年从该校毕业并获得软件开发专业的荣誉理学学士学位。他于 2006 年 11 月加入 IBM 都柏林软件实验室。他目前是爱尔兰都柏林的 SOA 团队的一员。 |
Matt Healy 是 IBM 爱尔兰公司的一名软件工程师。他曾在爱尔兰的都柏林理工学院攻读计算机科学。他于 2004 年从该校毕业并获得荣誉理学学士学位,接着又获得了 "Investigating Text Message Classification Using Case-base Reasoning" 的研究硕士学位。他于 2006 年 9 月加入 IBM 爱尔兰都柏林软件实验室。他目前是爱尔兰都柏林的 SOA 团队的一员。他在 AICS '05 上跟人合著了一篇参考文章 "An Assessment of Case-based Reasoning for Short Text Message Classification"。 |
Frederic Biava 是 IBM 爱尔兰公司的一名软件工程师。他毕业于法国的卢米尼马赛大学并获得计算机科学学士学位。接着在 2004 年从 Avignon 大学毕业并获得硕士学位(masters degree,D.E.S.S.)。他曾给 HP 公司担任了一年时间的技术支持。他于 2006 年 11 月加入 IBM 爱尔兰都柏林软件实验室。他目前是爱尔兰都柏林的 SOA 团队的一员。 |
Stephen Kruger 是 IBM 的 SOA Growth Projects 的一名 SOA 架构师,任职于爱尔兰的都柏林软件实验室。在此之前,他在法国的 Xeroxhe 研究中心领导高级开发工作,从事语言学和图像处理领域的项目以寻求文档管理方面的自动解决方案。在此之前,他在法国格勒诺布尔的 Sun Microsystems International Centre for Network Computing 担任 JavaSoft 工程师一职。 |
自由广告区 |
分类导航 |
邮件新闻资讯: IT业界 | 邮件服务器 | 邮件趣闻 | 移动电邮 电子邮箱 | 反垃圾邮件|邮件客户端|网络安全 行业数据 | 邮件人物 | 网站公告 | 行业法规 网络技术: 邮件原理 | 网络协议 | 网络管理 | 传输介质 线路接入 | 路由接口 | 邮件存储 | 华为3Com CISCO技术 | 网络与服务器硬件 操作系统: Windows 9X | Linux&Uinx | Windows NT Windows Vista | FreeBSD | 其它操作系统 邮件服务器: 程序与开发 | Exchange | Qmail | Postfix Sendmail | MDaemon | Domino | Foxmail KerioMail | JavaMail | Winwebmail |James Merak&VisNetic | CMailServer | WinMail 金笛邮件系统 | 其它 | 反垃圾邮件: 综述| 客户端反垃圾邮件|服务器端反垃圾邮件 邮件客户端软件: Outlook | Foxmail | DreamMail| KooMail The bat | 雷鸟 | Eudora |Becky! |Pegasus IncrediMail |其它 电子邮箱: 个人邮箱 | 企业邮箱 |Gmail 移动电子邮件:服务器 | 客户端 | 技术前沿 邮件网络安全: 软件漏洞 | 安全知识 | 病毒公告 |防火墙 攻防技术 | 病毒查杀| ISA | 数字签名 邮件营销: Email营销 | 网络营销 | 营销技巧 |营销案例 邮件人才:招聘 | 职场 | 培训 | 指南 | 职场 解决方案: 邮件系统|反垃圾邮件 |安全 |移动电邮 |招标 产品评测: 邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端 |