设计支持 WS-I 标准的 Web服务(三)

日期: 2007-12-13 作者:Parlione 来源:TechTarget中国

  实现

  在本节中,我们将描述 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 所示的警告:

  图 2. IBM Lotus Domino Designer 错误对话框
 
  数组作为参数和返回值

  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 数组)。

  清单 1 . AuthorDTOArray_Holder 示例
Class AuthorDTOArray_Holder as INOUT_HOLDER
‘The AuthorDTO array holder class
Public value() As AuthorDTO


End Class
 
  清单 2. 生成的 WSDL
<complexType name=”AUTHORDTOArray”>
  <sequence>
     <element maxOccurs=”unbounded” minOccurs=”0″ name=”item” type=”impl:AUTHORDTO”/>
  </sequence>
</complexType>

  不幸的是,没有说明如何将数组作为参数传递给 LotusScript Web 服务方法。 在开发 Discussion 数据库 Web 服务期间,我们尝试了两种不同的方法,直接传递数组(清单 3)以及对原语类型和复杂类型使用 holder 类(清单 4)。

  清单 3. 直接传递数组的示例
 Sub markListRead(ids() As String)

End Sub

Sub markTopicsRead(topics() as TopicDTO)

End Sub
   
  清单 4. 使用数组 holder 类的示例
 Sub markListUnread(ids As STRINGARRAY_HOLDER)

End Sub

Sub 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 所示错误消息的客户机。

  清单 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)使数组生效。

  清单 6. 生成的 WSDL
  
<complexType name=”ArrayOf_xsd_string”>
 <complexContent>
  <restriction base=”soapenc:Array”>
   <attribute ref=”soapenc:arrayType” wsdl_arrayType=”xsd:string[]”/>
  </restriction>
 </complexContent>
</complexType>
   
  清单 7. 手工编辑的 WSDL
<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 所示。

  清单 8. IDList 示例
Class IDList

 Public ids() As String

 Public type As String

End Class
   
  Null 值和复杂类型

  LotusScript 原生数据类型(如 String、Integer 或 Boolean)不允许使用 null 值。要使用 null 值,比如,要为主题 DTO 中的 body 字段传递一个 null 值,我们使用 lsxsd.lss 库中的数据类型(如 XSD_String 或 XSD_Boolean),这些类型允许使用 null 值。清单 9 展示了带有 XSD_String 类型字段的 TopicDTO 类,清单 10 中生成的 WSDL 的相应部分显示,body 属性可以为空。

  清单 9. TopicDTO 示例
Class TopicDTO
 Public body As XSD_STRING
 …
End Class
   
  清单 10. TopicDTO WSDL 片段
 <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。

  清单 11. Lotus Domino V8 的 createResponse 示例
 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,原因同上。

  清单 12. Lotus Domino V7 的 createResponse 示例
  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 分支中的代码。

  清单 13. LotusScript 版本检查示例
 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
 

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

作者

Parlione
Parlione

相关推荐

  • SAP收购CallidusCloud 与Salesforce竞争

    一直被称为后台办公巨头的SAP现在似乎也想在前台办公大展拳脚。 最新的迹象是SAP收购CallidusClou […]

  • 事件驱动框架和SOA在空军的应用

    空军正在利用SOA来改善数据共享,并实时跟踪战机,美国空军机动司令部的Michael Marek解释了企业可从中学习的经验。

  • 揭秘New Relic APM技术细节

    New Relic应性能管理(APM)套件主要用于Web软件开发。它允许用户在面向服务的架构(SOA)上跟踪关键事务性能,并且支持代码级别的可见性来评估特定代码段和SQL语句对性能的影响

  • 仅凭SOA和云无法解决业务数据管理风险问题

    SOA和云可以是某些恼人问题高效的解决方案;这一点我们已经知道了。但是也要记住它们并不是所有事情的直接答案,特别是当你的问题是业务数据管理风险,而不是技术问题时。