内容


使用 WebSphere Integration Developer V6.2.0.1 中的 Claim Check 模式提高应用程序效率

Comments

简介

为使应用程序高效运行,您不希望它携带多余数据 —— 应用程序不需要的数据。携带过多的数据有一些负面影响,这包括增加的内存使用率、数据模型的紧耦合,以及 Java™ 环境中增多的垃圾回收。这些会导致更频繁的应用程序版本控制。

但是,您的应用程序很多时候没有仅选择所需数据的权利。例如,您的应用程序可能与标准相符,且需要使用一个行业标准消息格式作为其接口。这往往会很大且很复杂,这样它们才能为设计的业务处理所有用例。然而,您的应用程序只需要该行业标准消息上的少量数据来达到处理目的。幸运的是,应用程序设计人员学习并记录了一种好方法,可以使用 Claim Check 模式处理这个问题。

Claim Check 背后的理念很简单:

  • 通过将数据存储到一些永久性数据存储中而收起(或 “分离”)应用程序不需要的数据。
  • 让应用程序在数据量尽量小的情况下高效运行。
  • 最后有需要时,在继续处理之前从永久性数据存储中检索数据。

使用一个真实类比,当您乘飞机旅行时,要签入托运大件行李且只要在到达中转点或目的地时才领取它们。Claim Check 模式基本上适用于这个生活常识和 IT 有效实践。图 1 从概念上解释了 Claim Check 的运作方式。在图中,“M” 表示一个应用程序的输入消息,“A” 表示输入消息包含的大型附件内容。

在签入期间,附件存储在一个永久性数据存储中且返回一个 “T” 令牌。“T” 要存储在某个地方,在图 1 中,它是作为消息 “M” 的一部分被存储的。然后轻量级消息 “M” 由应用程序处理,在此期间可能发生转换。

应用程序输出一个转换后的消息 “M**”。在进一步处理之前(例如,调用另一个应用程序),当使用令牌 “T” 从数据存储中检索附件 “A” 且将 “A” 附着于转换后的消息 “M**” 时,就发生了签出。注意,图 1 从概念上解释了 Claim Check。

在现实中,应用程序可以在需要附件时签出附件 “A”。“签入” 和 “签出” 组件不一定是应用程序的一部分。签出附件 “A” 之后,不一定会立即从数据存储中删除它。

图 1. Claim Check 模式解决方案
Claim Check 模式解决方案
Claim Check 模式解决方案

欲了解关于 Claim Check 模式的更多信息,请参阅 参考资料 部分中列出的集成模式图书。

在应用 Claim Check 模式时,不管底层平台是什么,都需要考虑以下三方面:

  1. 单个附件 vs. 多个附件
  2. 逻辑附件 vs. 物理附件
  3. 数据导航简化

首先,我们使用术语 “附件” 表示希望凭证索取的数据。附件可以是一个 PDF 或 DOC 文件、一个 XLS 电子表格、一幅二进制图像,或一个视频或音频多媒体文件。大多数情况下,您的应用程序根本无需处理附件。因此,最好尽早分离附件并尽可能晚地重新附着它,且仅在需要时才重新附着。一个附件示例是一个大型工程绘图。单个附件 vs. 多个附件 仅表示是否只有一段数据(通常是输入消息中的一个字段)您需要凭证索取,或是否有多段数据您需要凭证索取。

逻辑附件 是指附件在消息中存储时,其字段或位置不是由供附件显式使用的消息架构定义的。一些消息传送标准有在消息内定义显式字段或位置的架构,用于存储附件。一个示例就是 Web 服务标准。当一条消息内一个附件的位置由消息架构良好定义时,我们将该附件看作本文所讲的物理附件

凭证索取的目的是要提高效率。当应用程序不需要的数据被分离时,应用程序就会在仅携带所需数据的情况下运行,因而更有效。不过,较少的数据不一定表示应用程序可以轻松导航到它需要的数据。如果应用程序要处理的消息有一个复杂的架构,应用程序获取其需要的数据就要做更多的工作。因此,在应用凭证索取模式时,为何不一并考虑最大限度地降低应用程序所需的导航?为此,除了凭证索取应用程序不需要的数据之外,您可以将其余数据映射到一个更小且轻量级的业务对象中,让应用程序处理该业务对象。

应用凭证索取的一个现实示例是,处理遵循某个行业标准(比如 ACORD)的一条的输入消息。应用程序只需要使用大型 ACORD XML 消息的一些分支中的数据子集。可凭证索取大型 ACORD XML 消息的其余分支和消息附件。

本文使用了一个样例场景来展示凭证如何索取逻辑附件和物理附件。本文随带的 样例应用程序 展示了样例场景,并包含一个凭证索取服务,您可以将其作为基础来开发自己的应用程序。

何时使用 Claim Check

客户很多时候会问,他们为何需要使用 Claim Check 模式且何时使用它。毕竟,在使用 64-bit JVMs 时,WebSphere Process Server(以下简称 Process Server)和 WebSphere Enterprise Service Bus (ESB) 都可以利用数千兆字节的堆内存,这表示,它们可以处理上百兆字节的一条消息或几十兆字节的多条消息。一般而言,我们不推荐通过 Process Server 和 WebSphere ESB 传递大容量消息,特别是在它们没有多少用处时。

Process Server 和 WebSphere ESB 拥有显式功能来处理附件,如 用 WebSphere Integration Developer V7 实现 SOA 应用程序中的附件功能 一文所述。但是,仅仅因为您可以做某件事情,并不代表您应该去做。

那么何时应用 Claim Check 模式呢?首先,想象您在使用 Process Server 和 WebSphere ESB 构建什么类型的解决方案。相关背景知识,请参阅 WebSphere Process Server 和 WebSphere ESB 中的解决方案设计,第 1 部分: WebSphere Process Server 内的解决方案介绍

最关键的问题是:

  1. 您是否有大容量消息或业务对象?
  2. 是否有很多不必要的元素是 Process Server 和 WebSphere ESB 解决方案不需要的?
  3. 大容量消息的处理会导致资源限制并阻碍其他 Process Server 解决方案的处理吗?
  4. 是否有其他系统需要的未使用元素?
  5. 未使用元素是否集中在一起(比如,附件)?

决策过程参见图 1A 中的流程图。

图 1A. Claim Check 模式解决方案
Claim Check 模式解决方案
Claim Check 模式解决方案

样例应用程序概述

样例应用程序 阐释了逻辑和物理附件的处理。它包含 4 个模块:

  1. ClaimCheck 模块
  2. OrderProcessing 模块
  3. OrderToShipment 模块
  4. ShipmentProcessing 模块

ClaimCheck 模块

ClaimCheck 模块是 Claim Check 服务的一个样例实现。它实现 ClaimCheckIntf 接口,包含三个操作:一个用于签入附件,一个用于签出附件,还有一个用于清理存储附件的永久性数据存储。在 样例应用程序 中,文件系统用作持久性数据存储。凭证索取服务使用一个平面文件适配器来从文件系统中读写附件。

当一个调用方需要签入一个附件时,它调用 Claim Check 服务,传入一个 ClaimCheckObject 类型的数据对象。Claim Check 服务返回 TicketEnvelope 类型的一个令牌给调用方。在样例应用程序中,由于文件系统用于存储附件,返回给调用方的令牌是写入附件内容的文件的名称。调用方需要存储令牌,这样一来,稍后就可以使用它从 Claim Check 服务中检索附件。在样例应用程序中,令牌存储在数据对象中,存储在分离附件所基于的同一字段中。最后,当调用方需要签出附件时,它使用令牌调用 Claim Check 服务,附件返回调用方。

尽管样例应用程序为简便而使用文件系统作为永久性数据存储,正如您稍后就看到的,我们在 ClaimCheck 模块内提供了逻辑,来阐释如何使用附加存储类型,比如一个队列或一个数据库。由于我们的样例应用程序中的永久性数据存储和附件不计划长期维护,为了避免不必要的存储尺寸增长,在签出附件之后需要将其清除。Claim Check 服务样例提供了一个操作,支持了客户端在索取附件之后将其从数据存储中删除。客户端需要显式调用这个操作来从数据存储中删除过期的附件数据。

OrderProcessing 模块

OrderProcessing 模块实现一个简单的中介,将 GenericOrderProductItem 类型的两个独立对象作为输出,并生成 Order 类型的一个对象作为输出。OrderProcessing 模块内的中介逻辑接受 ProductItem 对象并将其转化成 Order 对象的一个逻辑附件。然后 OrderProcessing 模块使用 Order 对象调用 OrderToShipment 模块。

OrderToShipment 模块

OrderToShipment 模块包含样例应用程序的大部分逻辑。逻辑分为两个主要部分。第一部分使用 Claim Check 服务处理逻辑附件的签入和签出,而第二部分为物理附件执行同样的功能。

图 2 描述 OrderToShipment 模块中的第一部分逻辑。

图 2. 逻辑附件的 Claim Check 模式解决方案
逻辑附件的 Claim Check 模式解决方案
逻辑附件的 Claim Check 模式解决方案

ProcessOrderService 导出(在图 2 中标记为 “1”)调用 ClaimCheckDataHandler,这是一个自定义数据处理程序,有一个名为 CheckinConfiguration 的数据处理程序配置。数据处理程序将逻辑附件从 Order 数据对象中分离出来,并调用 Claim Check 服务来签入逻辑附件。当 Claim Check 服务返回一个令牌时,令牌存储在 Order 数据对象中,存储在过去用于存储逻辑附件的同一字段中。CreateShipment 中介将 Order 数据对象转换成 ShipmentRequisition 数据对象。令牌也被复制到 ShipmentRequisition 数据对象中。

ProcessShipment导入(在图 2 中标记为 “2”)使用另一个名为 CheckoutConfiguration 的数据处理程序配置调用 ClaimCheckDataHandler。数据处理程序使用存储在 ShipmentRequisition 内的令牌调用 Claim Check 服务,以签出逻辑附件。ShipmentRequisition 内的令牌的位置在 CheckoutConfiguration 中指定。当 Claim Check 服务返回逻辑附件时,数据处理程序将逻辑附件附加在 ShipmentRequisition 数据对象上。最后,ProcessShipment 调用 ShipmentProcessing 模块,将其传递给带逻辑附件的 ShipmentRequisition 数据对象。

图 3 描述 OrderToShipment 模块中的第二部分逻辑,该部分处理物理 Web 服务(SOAP) 附件的签入和签出。

图 3. 物理附件的 Claim Check 模式解决方案
物理附件的 Claim Check 模式解决方案
物理附件的 Claim Check 模式解决方案

OrderToShipment 模块的导出可由任何 Web 服务客户端调用。客户提供一个 Order Web 服务消息,将物理附件作为输入。ProcessIncomingAttachment 中介(在图 3 中标记为 “1”)分离 Web 服务附件并通过调用 Claim Check 服务签入附件。当 Claim Check 服务返回一个令牌时,令牌存储在 Order 数据对象内,存储在过去用于存储物理附件的同一字段中。CreateWSShipment 中介将 Order 数据对象转化为一个 ShipmentRequisition 数据对象。

ProcessOutgoingAttachment 中介(在图 3 中标记为 “2”)使用令牌调用 Claim Check 服务,通过这种方式签出物理附件。当 Claim Check 服务返回物理附件时,ProcessOutgoingAttachment 将物理附件附加到 ShipmentRequisition 数据对象并使用它调用 ShipmentProcessing 模块。

比较图 2 和图 3,会发现前者处理逻辑附件,而后者处理物理附件,除此之外还有两个主要区别。第一个区别是,在图 2 中使用了 OrderProcessing 模块而在图 3 中没有。OrderProcessing 模块在逻辑附件场景中充当测试客户端的角色,以逻辑附件为输入创建一个 Order 数据对象到 OrderToShipment 模块中。

在物理附件场景中,使用 WebSphere Integration Developer(以下简称 Integration Developer)测试客户端发送一个带物理附件的 Web 服务(SOAP)消息是很简单的,因此不需要 OrderProcessing 模块。因此,第一个区别是由于我们尝试使样例应用程序易于测试而出现的,且它对 Claim Check 模式解决方案的设计没有任何意义。图 2 与图 3 的第二个区别在于,对于逻辑附件,自定义数据处理程序用于调用 Claim Check 服务,而对于物理附件,则未使用自定义数据处理程序。

Claim Check 服务由 ProcessIncomingAttachmentProcessOutgoingAttachment 这两个中介调用。这第二个区别对于 Claim Check 模式解决方案的设计很重要。它是因 SCA Web 服务绑定实现的一个当前限制产生的。正如 简介 部分所提,最好尽早分离附件并尽量晚地重新附着它。因此,通过自定义数据处理程序在输出和输入中调用 Claim Check 服务是一个很好的设计。不过,对于一个 Web 服务物理附件,Integration Developer 和 WebSphere ESB 目前不支持同样的方法。因此,我们选择直接从图 3 中的中介调用 Claim Check 服务。

ShipmentProcessing 模块

ShipmentProcessing 模块记录样例应用程序处理的结果。它被实现为一个 Java 组件,该组件将接收到的数据写到系统输出上。如果应用程序运行正确,写到测试环境系统输出文件的消息包含数据对象的序列化 XML 内容,包括签出的附件。

Claim Check 服务实现

在本节中。我们描述 Claim Check 服务实现。我们首先将解释使用的接口和接口上的数据类型。然后,我们将描述 Claim Check 服务中的请求和响应流,然后描述样例应用程序中 Claim Check 使用的底层平面文件数据存储的配置。

样例应用程序 将 Claim Check 作为一个名为 “ClaimCheck” 的 SCA 模块予以实现。它使用一个名为 ClaimCheckExport 的 SCA 导出作为入口点,如图 4 所示。

图 4. ClaimCheck 模块组装图
ClaimCheck 模块组装图
ClaimCheck 模块组装图

图 5 显示,ClaimCheckExport 通过三个操作将 ClaimCheckIntf 接口公开给客户端:

  • checkin:该操作由客户端调用,用于签入一个附件。它接受 ClaimCheckObject 类型的一个对象,该对象将附件包装为一个输入,并在 TicketEnvelope 类型的数据对象中返回一个索取令牌。
  • checkout:该操作用于签出一个附件。它接受 TicketEnvelope 类型的数据对象中的索取令牌,并返回包转附件的 ClaimCheckObject 类型的 Claim Check 数据对象。
  • cleanup:该操作用于存储维护。签出附件之后,用户可能希望清理存储,除非出于调试或其他原因而需要永久存储附件。清除操作接受 TicketEnvelope 类型的数据对象中的索取令牌来定位并从存储中删除附件内容。
图 5. Claim Check 服务接口
Claim Check 服务接口
Claim Check 服务接口

ClaimCheckObject 有两个元素,如图 6 所示:

  • data:该元素包含传递给 Claim Check 服务的真正附件对象。因为它需要包含任何对象类型,其类型被定义为 anyType
  • storetype:该元素确定 Claim Check 服务应使用的存储类型。有效值集为:FF(文件系统) 、DB(数据库)和 QUEUE(队列)。只有 FF(文件系统)选项由样例应用程序实现。其他两个存储选项的实现不予提供,不过您可以轻松添加它们。
图 6. 包装附件的 ClaimCheckObject
包装附件的 ClaimCheckObject

TicketEnvelope 有两个元素,如图 7 所示:

  • claimtoken:该元素包含字符串形式的索取令牌。在我们的样例应用程序中,令牌就是用于存储附件的文件名。在其他情况下,它可以是数据库或其他应用程序上的记录 ID。
  • storetype:当令牌用于签出存储中的附件内容时,该元素确定 Claim Check 服务使用的存储类型。在我们的样例应用程序中,类型一直都是 FF,因为只有文件系统存储被实现了。但是,如果数据库或队列存储得到实现,那么您可以使用该标志从相应存储类型中获取附件。
图 7. 包装索取令牌的 TicketEnvelope
包装索取令牌的 TicketEnvelope

中介组件 ClaimCheckAdapterMapper 的请求流实现对于 ClaimCheckIntf 接口上的三个操作都是类似的,且包含两个步骤(见图 8):

  1. 第一步是使用消息过滤器 SelectStoreType 基于输入数据对象中的 storetype 元素值选择存储类型。对于 checkin,ClaimCheckObject 是输入数据对象。对于 checkout 和 cleanup,TicketEnvelope 是输入数据对象。
  2. 第二步是从 ClaimCheckIntf 接口使用的数据对象到特定适配器接口使用的数据对象的一个简单转换,这个适配器接口由平面文件资源适配器 FlatFileImport1 定义。注意,数据库和队列存储类型的流使用自定义中介原语来记录请求到达的事实。
图 8. Claim Check 服务 checkin 操作的请求流
Claim Check 服务 checkin 操作的请求流
Claim Check 服务 checkin 操作的请求流

中介组件 ClaimCheckAdapterMapper 的请求流实现对于 checkin 和 checkout 操作是类似的(参见图 9 和图 10)。请求流包括平面文件接口 FlatFileImport1 和凭证索取服务接口 ClaimCheckIntf 使用的业务对象的转换。cleanup 操作是一种单向操作,因而没有响应流。

图 9. Claim Check 服务 checkin 操作的响应流
Claim Check 服务 checkin 操作的响应流
Claim Check 服务 checkin 操作的响应流
图 10. Claim Check 服务 checkout 操作的响应流
Claim Check 服务 checkout 操作的响应流
Claim Check 服务 checkout 操作的响应流

图 11 中对 EIS 平面文件导入绑定组件 FlatFileStore 进行配置,以将 ClaimCheckObject 以 XML 格式写到 C:\FlatFilesAny 的文件系统位置。每个附件的文件名也在 EIS 绑定配置中得到定义。“Default target file name” 定义文件名的常量部分。作为文件名后缀的顺序索引由绑定生成,且存储在 “Sequence file” 指定的文件中。

图 11. FlatFileStore EIS 导入组件配置
FlatFileStore EIS 导入组件配置
FlatFileStore EIS 导入组件配置

FlatFileStore 使用特定适配器生成的接口 FlatFileImport1(见图 12)。在 FlatFileImport1 接口定义的操作与 ClaimCheckIntf 接口定义的操作之间有一个一对一的映射(参见 图 5)。文件名由 FlatFileImport1 接口的 Create 操作自动返回。然后样例应用程序将该文件名用作一个索取令牌,用于签出附件。

retrieveFlatFile 操作将包装在 FlatFile 数据对象中的文件名作为输出,然后返回在输出目录中找到的给定名称的文件(参见图 11 中的 “Output directory” 字段)。deleteFlatFile 操作也将包装在 FlatFile 数据对象中的文件名作为输出,然后从输出目录中删除给定名称的文件。

图 12. FlatFileImport1 接口
FlatFileImport1 接口
FlatFileImport1 接口

平面文件导入绑定组件 FlatFileStore 是使用 EIS 外部服务发现构建的,该服务通过 File > New > External Service 菜单调用。Integration Developer 文档提供了有关如何创建和使用 EIS 绑定的扩展文档,比如 Accessing external services with adapters

ClaimCheck 模块对于逻辑附件是从一个数据处理程序(图 2)被调用,而对于物理附件则是从自定义中介原语(图 3)被调用。两种情况都使用 Java 代码来调用 Claim Check 服务。为了封装大部分服务特定调用代码,一个名为 ClaimCheckInvoker 的 Java 类被创建,以供数据处理程序和自定义中介原语作为外观使用。您可以打开以下文件从 J2EE 角度查看 ClaimCheckInvoker 的源码:OrderToShipment/gen/src/text.handler/ClaimCheckInvoker.java.

ClaimCheckInvoker 实现一个以 SCA 引用伙伴名为参数的构造函数(参见 图 13)。checkIn 方法通过调用 Claim Check 服务允许客户端检查附件。checkIn 方法调用自数据处理程序(图 2)和自定义中介(图 3),后者以 DataObject 类型的附件作为输入参数,且使用存储类型来签入附件。它使用引用伙伴名定位 Claim Check 服务。然后它创建包装 ClaimCheckObject 数据对象并在包装中设置作为 DataObject 传入的附件。它还设置用于存储附件的存储类型。样例应用程序使用 FlatFile 适配器仅实现文件系统存储类型(“EF”)。最后,Claim Check 服务上的 checkin 操作被调用,且存储附件的文件名返回到调用客户端代码(清单 2)。

清单 1. ClaimCheckInvoker 的构造函数
public class ClaimCheckInvoker
{
    //Wrapper Claim Check business object name and its elements
    private String claimCheckWrapperNamespace = "http://CommonLibrary";
    private String claimCheckWrapperName = "ClaimCheckObject";
    private String claimCheckDataWrappingElement = "data";
    private String claimCheckSerTypeElement = "storetype";
    private String serviceRefName;
    
    public ClaimCheckInvoker(String claimCheckReferenceName) {
		serviceRefName = claimCheckReferenceName;
    }
    //Other code in the ClaimCheckInvoker class
}
清单 2. 附件的 ClaimCheckInvoker checkin
public DataObject checkIn(DataObject attachment, String storetype) 
{
	//Get a service manager to locate the service reference.
    	ServiceManager serviceManager = ServiceManager.INSTANCE;
        
    //Locate claim check service.
	Object claimCheckService = 
		serviceManager.locateService(serviceRefName);
    	
    	//Locate a BO factory service to create the input data object.
    	BOFactory boFactory = 
		(BOFactory)serviceManager.
		locateService("com/ibm/websphere/bo/BOFactory");

      System.out.println("Found service object: " + claimCheckService);
    	
      if (claimCheckService instanceof Service)
      {
      //Now we create a new instance of the ClaimCheck service 
	  //input data object.
        DataObject claimCheckDataobject = 
		boFactory.create(claimCheckWrapperNamespace, claimCheckWrapperName);

      //The attachment data represents a data object itself. So we use 
	  //setDataObject method to set the data.
      	claimCheckDataobject.
			setDataObject(claimCheckDataWrappingElement, 
			attachment);
        	
      //Set the store type.
       	claimCheckDataobject.setString(claimCheckSerTypeElement,
			storetype);
        	
     //Invoke the Claim check service and return the claim token data 
	 //object that contains the file name.
        	DataObject claimToken =(DataObject)
			((Service)claimCheckService).
			invoke("checkin", claimCheckDataobject);
        	System.out.println(claimToken);
        	return claimToken;
      }

   	returnnull;
}

ClaimCheckInvoker 类实现的另一个方法是 checkOut 方法。checkout 方法接受一个票证作为 DataObject。从数据处理程序(图 2)和自定义中介原语(图 3)调用了同样的方法。该方法也接受一个 boolean 输入参数,指明签出附件之后是否需要清理存储。它使用引用伙伴名定位 Claim Check 服务,调用 Claim Check 服务上的 checkout 方法,从 Claim Check 服务返回的对象上提取附件,根据需要清理存储,最后将附件返回给调用方。

清单 3 显示了签出附件的 checkout 方法。参考 下载 部分中的项目交换文件,查看另一个 checkout 方法的代码。

清单 3. 附件的 ClaimCheckInvoker checkout
public DataObject checkOut(DataObject ticket, boolean performCleanup)
{
	//Get a service manager to locate the service reference.
    	ServiceManager serviceManager = ServiceManager.INSTANCE;

    	//Locate claim check service.
    	Object claimCheckService = 
		serviceManager.locateService(serviceRefName);
    	
      System.out.println("Claim token passed in: " + ticket.toString());
    	
      if (claimCheckService instanceof Service)
      {
 
      //In this case the ticket is a data object itself.
      	if (ticket != null)
        	{
        //Invoke the operation by passing the operation name and an 
		//input argument. 
            	Object checkedOut =  
				((Service)claimCheckService).invoke("checkout", 
				ticket);
            	
		//Get the attachment checked out data object from the 
        //wrapper.
            DataObject output = ((DataObject) 
			((DataObject)checkedOut).get(0)).
				getDataObject(claimCheckDataWrappingElement);
            	
            System.out.println(output);
        	if (performCleanup)
        	{
		//If the data handler is configured to clean up the storage 
        //after the checkout then we need to invoke the cleanup 
        //operation
                	((Service)claimCheckService).invoke("cleanup", 
				ticket);
        	}
            return output;
        }
    }

    returnnull;
}

对逻辑附件使用 Claim Check

本节解释 样例应用程序 如何应用于逻辑附件场景。

该场景的入口点是 OrderProcessing 模块中的中介组件 AddLogicalAttachmentToOrder,如图 13 所示。

图 13. OrderProcessing 模块组装图
OrderProcessing 模块组装图
OrderProcessing 模块组装图

AddLogicalAttachmentToOrder 中介组件使用一个单向操作实现 OrderPrepareInterface 接口,该操作接受两个输入参数:GenericOrder 类型的 OrderInProductItem 类型的 ProductItemIn(图 14)。

图 14. OrderPrepareInterface 接口
OrderPrepareInterface 接口
OrderPrepareInterface 接口

AddLogicalAttachmentToOrder 中介使用一个 XSL 转换将 ProductItemIn 数据对象作为逻辑附件附着到 OrdersInterfaceOrder 类型的 inputOrder 数据对象(见图 15)。图 16 显示了 XSL 转换。注意,除了在 inputOrder 数据对象中创建逻辑附件之外,orderIn 数据对象中的其他字段,比如 idamount,也被复制到 inputOrder 数据对象。

图 15. OrdersInterface 接口
OrdersInterface 接口
OrdersInterface 接口
图 16. AddLogicalAttachmentToOrder 内的转换
AddLogicalAttachmentToOrder 内的转换
AddLogicalAttachmentToOrder 内的转换

带有附件的 inputOrder 数据对象创建好之后,它被传递给 HTTP 导入绑定组件 ProcessOrder(图 17)。对绑定组件进行配置以调用 OrderToShipment 模块。

图 17. OrderProcessing 模块的 HTTP 导入
OrderProcessing 模块的 HTTP 导入
OrderProcessing 模块的 HTTP 导入

请求到达 OrderToShipment 模块的 HTTP 导出绑定组件 ProcessOrderService(图 18)。

图 18. 逻辑附件的 OrderToShipment 组装图
逻辑附件的 OrderToShipment 组装图
逻辑附件的 OrderToShipment 组装图

ProcessOrderService 导出被配置为使用自定义数据处理程序配置 CheckinConfiguration(图 19),而后者反过来被配置为调用自定义数据处理程序 ClaimCheckDataHandler(图 20)。

图 19. 自定义数据处理程序配置 CheckinConfiguration
自定义数据处理程序配置 CheckinConfiguration
自定义数据处理程序配置 CheckinConfiguration
图 20. CheckinConfiguration 属性
CheckinConfiguration 属性
CheckinConfiguration 属性

自定义数据处理程序配置 CheckinConfiguration 有很多属性:

  • attachmentElementName 指定传入的数据对象中的字段,也就是逻辑附件所在。之前我们提到过,逻辑附件被移动到 inputOrder 数据对象的 productItem 字段中,目的是调用 OrderToShipment 模块(见图 16)。因此,图 20 中指定的 attachmentElementName 属性的值是 productItem
  • 如果选中 cleanUp 复选框,就表明在签出附件之后需要将其从永久性数据存储中移除掉。
  • localReferenceName 属性包含要调用的 Claim Check 服务的引用伙伴名。
  • 如果选中 storeToken 复选框,就表明 Claim Check 服务返回的索取令牌存储在传入的数据对象中,就是附件之前所在的位置。如果不选中 storeToken 复选框,索取令牌会被存储在临时上下文中。

自定义数据处理程序 ClaimCheckDataHandler 是通过其转换方法调用的。看一下代码中的注释就会明白转换方法的作用(清单 4)。转换方法调用的 ClaimCheckInvoker 在本文前面有介绍。注意,在临近转换方法的末尾,索取令牌(在我们的样例应用程序中,它是用于存储逻辑附件的文件的名称)被存储在 inputOrder 数据对象或临时上下文中。

清单 4. ClaimCheckDataHandler 的转换方法
public Object transform(Object incomingSourceStream, Class 
	targetObjectType, Object options)
      	throws DataHandlerException
{
	System.out.println("Transforming incoming message");
    	//Use XML Data handler to transform the data
    	XMLDataHandler handler = new XMLDataHandler();

	//Extract attachment from the data object using the configured 
    //element name
      Object currentObject = handler.transform(incomingSourceStream, 
		targetObjectType, options);
   	DataObject attachment = 
		((DataObject)((DataObject)currentObject).get(0)).
			getDataObject(logicalAttachmentElement);

       //Use claim check invoker to check the logical attachment in
       ClaimCheckInvoker invoker = new 
		ClaimCheckInvoker(claimCheckReference);

   	//Check in the attachment using the Flat File store type
   	Object fileName = invoker.checkIn(attachment, "FF");
   		
   	//Store the file name in the Data Object or transient context. 
   	if (storeTokenInBo)
   		((DataObject)((DataObject) currentObject).get(0)).
			set(logicalAttachmentElement, 
				((DataObject)fileName).get(0));
   	else
   		com.ibm.wsspi.session.ContextService.INSTANCE.getContext().
			setTransient(((DataObject)fileName).get(0));

   	System.out.println("Here is the data object with removed logical 
		attachment:");
   	printDataObject((DataObject)currentObject);
   		
   	return currentObject;
   	}

参考上面 图 3,数据处理程序的 transform 方法返回后,更新的 inputOrder 数据对象(逻辑附件被索取令牌替换)被传递给 CreateShipment 中介组件。该中介组件将 inputOrder 数据对象转换成(ShipmentRequisition 类型的)inputShipmentInfo 数据对象。注意,索取令牌从 inputOrder 源数据对象的 productItem 元素移到 inputShipmentInfo 目标数据对象的 productDescription 元素(图 21)。

图 21. CreateShipment 内的转换
CreateShipment 内的转换
CreateShipment 内的转换

CreateShipment 中介组件完成转换之后,ProcessShipment HTTP 导入绑定组件被调用(图 22)。这个导入绑定组件被配置为发送一个 XML 格式的 HTTP POST 请求到目标 ShipmentProcessing 模块。另外,绑定组件被设置为使用自定义数据处理程序配置 CheckoutConfiguration。

图 22. 自定义数据处理程序配置 CheckoutConfiguration
自定义数据处理程序配置 CheckoutConfiguration
自定义数据处理程序配置 CheckoutConfiguration

与前面描述的 CheckinConfiguration 类似,CheckoutConfiguration 包含大量由自定义数据处理程序使用的属性。不过,这种情况是发生在 Claim Check 服务签出附件的过程中。

图 23. CheckoutConfiguration 属性
CheckoutConfiguration 属性
CheckoutConfiguration 属性

CheckoutConfiguration 中包含的属性是:

  • attachmentElementName 指定传入的数据对象中的字段,这里是找到索取令牌的地方,也是在从 Claim Check 服务上成功签出逻辑附件之后重新附着它的地方。我们之前提到过,索取令牌被移到 inputShipmentInfo 数据对象的 productDescription 元素中(参见 图 21)。因此,在图 23 中指定的 attachmentElementName 属性的值是 productDescription
  • 如果选中 cleanUp 复选框,就表明在签出附件之后需要将其从永久性数据存储中移除掉。
  • localReferenceName 属性包含要调用的 Claim Check 服务的引用伙伴名。
  • 如果选中 storeToken 复选框,就表明索取令牌位于传入的数据对象中,即附件之前所在的位置。如果不选中 storeToken 复选框,索取令牌就会位于临时上下文中。

相同的数据处理程序类 ClaimCheckDataHandler 实现 transformInto 方法,该方法是为签出逻辑附件而被调用。transformInto 通过 ClaimCheckInvoker 调用 Claim Check 服务上的 checkOut 方法,将其传递给索取令牌和一个指示是否需要执行清理工作的 boolean 标志。成功签出附件之后,它被重新附着到数据对象 inputShipmentInfo 上。在 transformInto 方法末尾,将数据对象转换为 XML 消息的任务被委托给开箱即用的 XMLDataHandler(清单 5)。

清单 5. ClaimCheckDataHandler 的 transformInto 方法
publicvoid transformInto(Object sourceDataObject, Object 
	outputTargetStream, Object options)
        throws DataHandlerException
{
	System.out.println("transformInto invoked");

	if (sourceDataObject instanceof DataObject)
   	{
		//Use ClaimCheck service invoker to check out the logical 
        //attachment data. 
		//It uses a reference to the local reference that allows us 
        //to invoke the SCA import.
		ClaimCheckInvoker invoker = new 
			ClaimCheckInvoker(claimCheckReference);
   			
			
		DataObject ticket = null;
		//Extract claim token from the logical element of the BO or 
        //the context
   		if (storeTokenInBo)
   			ticket = (DataObject) ((DataObject) sourceDataObject).
				get(logicalAttachmentElement);
   		else
			ticket = (DataObject)
			com.ibm.wsspi.session.ContextService.INSTANCE.
			getContext().getTransient();

		//Check out the attachment
		DataObject attachment = invoker.checkOut(ticket, 
			needsCleanUp);
   			
   		//Re-attach the attachment data to the parent data object
   		((DataObject) sourceDataObject).
			setDataObject(logicalAttachmentElement, attachment);
   	}
		
   	System.out.println("Here is the data object with re-attached 
		logical attachment:");
   	printDataObject((DataObject) sourceDataObject);
    	
   	//Use XML Data handler to transform the data
    	XMLDataHandler handler = new XMLDataHandler();
	handler.transformInto(sourceDataObject, outputTargetStream, 
		options);
}

在签出附件并将其重新附着于(ShipmentRequisition 类型的)inputShipmentInfo 数据对象之后,ProcessShipment 导入绑定组件发送一个 HTTP POST 请求到 ShipmentProcessing 模块。

参考图 24,当请求到达 ShipmentProcessing 模块时,ShippingHTTPExport 导出绑定组件将输入 XML 消息转换为一个数据对象,并将其传递给 Java 组件 ProcessShipmentComponentStub,该组件将数据对象的内容写到系统输出上。

图 24. ShipmentProcessing 模块的 HTTP 导出
ShipmentProcessing 模块的 HTTP 导出
ShipmentProcessing 模块的 HTTP 导出

上面内容详细描述了处理逻辑附件所用的 Claim Check 模式解决方案的样例实现。

对物理附件使用 Claim Check

Web 服务使用 Simple Object Access Protocol (SOAP) 通过 HTTP 传递消息。一个 SOAP 消息是一个遵循特定格式的 XML 文档:信封、头、正文和附件。由于 SOAP 消息格式包括显式附件字段,在本文中,我们将 SOAP 附件看作 “物理附件”,与前面描述的 “逻辑附件” 形成对比。在本节中,我们使用 样例应用程序 来展示如何应用 Claim Check 模式来处理 SOAP 附件。

我们的示例需要我们创建一个带附件的 SOAP 消息。这可以使用 Integration Developer 测试客户端简单完成,它支持发送一个带附件的 SOAP 消息来调用一个 Web 服务。在 Integration Developer 中,调用一个 Web 服务实际上意味着调用一个导出上的 Web 服务绑定。我们在后面将详细解释如何使用 Integration Developer 测试客户端。首先,我们重点介绍使用 Integration Developer 和 Process Server V6.2.0.1 处理 SOAP 附件的 Claim Check 模式解决方案的关键方面。两个主要方面是:

  • 在执行业务逻辑之前将一个 SOAP 附件签入 Claim Check 数据存储中。
  • 从 Claim Check 数据存储中签出附件并将其重新附着到 SOAP 消息上。

签入和签出 SOAP 附件实际上是对 SOAP 消息的操作。Process Server 提供 Service Message Object (SMO) APIs,允许用户操作 SOAP 附件。在 样例应用程序 中,我们使用两个中介组件中的这些 APIs,这两个中介组件是 OrderToShipment 模块中的 ProcessIncomingAttachment 和 ProcessOutgoingAttachment。图 25 显示了 OrderToShipment 模块组装图中的两个中介组件。

图 25. 物理附件的 OrderToShipment 组装图
物理附件的 OrderToShipment 组装图
物理附件的 OrderToShipment 组装图

ProcessIncomingAttachment 组件负责将一个 SOAP 附件存储到 Claim Check 数据存储中,方式是使用 checkInAttachment 包含以下 Java 片段(清单 6)的自定义中介原语。

清单 6. 用于签入 SOAP 附件的 Java 片段
//Get SOAP attachment contents
AttachmentType attachment = (AttachmentType)smo.getAttachments().get(0);
System.out.println("Detaching the attachment and checking it in using 
 the ClaimCheck service as a byte array: " + attachment.getData());

//Locate a BO factory service to create the input data object.
BOFactory boFactory = (BOFactory)ServiceManager.INSTANCE.
	locateService("com/ibm/websphere/bo/BOFactory");

//Now we create a new instance of the ClaimCheck service input data object.
DataObject claimCheckDataobject = boFactory.
	create("http://CommonLibrary", "ClaimCheckObject");
//Attachment is passed in as a byte array so we need to use the method 
//setBytes to set the data.
claimCheckDataobject.setBytes("data", attachment.getData());

ClaimCheckInvoker invoker = 
	new ClaimCheckInvoker("ClaimCheckIntfPartner");
//Invoke checkin method passing the default store as Flat File to store 
//the data on the file system
DataObject returnValue = invoker.checkIn(claimCheckDataobject, "FF");

//extract the file name from the returned object and then store this 
//name as a text string.
DataObject returnToken = ((DataObject)returnValue).
	getDataObject("token");
String fileName = returnToken.getString("claimtoken");

//Attaching the file name of the file containing the attachment 
//content as an attachmnet to the SMO
System.out.println("Attaching the file name containing the attachment 
 contents to the SMO: " + fileName);
attachment.setData(((String)fileName).getBytes()); 
out.fire(smo); 
// propagate the service message object to the primitive that is 
//wired to the 'out' terminal

注意,Claim Check 服务返回的索取令牌存储在 SOAP 附件之前所在的同一位置,因此稍后可使用该令牌获取 SOAP 附件。

由于 SOAP 附件的签入,从 ProcessIncomingAttachment 组件传出的消息是一个轻量级消息,可由另一个组件(比如我们样例应用程序中的 CreateWSShipment 组件)内的业务逻辑轻松使用。不过,除了执行业务功能之外,CreateWSShipment 组件需要做的一件很重要的事是将索取令牌(附件文件名)从传入的消息移到传出的消息中(图 26)。不这样做会阻止下游组件使用索取令牌来获取 SOAP 附件。

图 26. CreateWSShipment 内的转换
CreateWSShipment 内的转换
CreateWSShipment 内的转换

完成业务逻辑之后,如果必要,需要签出 SOAP 附件并将其重新附着到 SOAP 消息中。在我们的样例应用程序中,我们假定需要签出 SOAP 附件,且 ProcessOutgoingAttachment 组件(参见 图 25)负责使用名为 CheckOutAttachment (清单 7)的一个自定义中介原语签出附件。

清单 7. 用于签出 SOAP 附件的 Java 片段
AttachmentType attachment = (AttachmentType)smo.getAttachments().get(0);

//Get the file name from the attachment. This file name will be used to 
//check the attachment contents out from the ClaimCheck service
byte[] fileNameBytes = attachment.getData();
String fileName = new String(fileNameBytes);

System.out.println("Using the ClaimCheck file name from the attachment 
 to check the real attachment from the ClaimCheck store: " + fileName);

//In this case the ticket passed to this method is a byte array. 
//So we need to construct the data object to invoke the service. 
BOFactory boFactory = (BOFactory)ServiceManager.INSTANCE.
	locateService("com/ibm/websphere/bo/BOFactory");
//Creating a new input data object.
DataObject ticketBO = boFactory.
	create("http://CommonLibrary", "TicketEnvelope");
//The ticket is the text representing the file name. So we can use this 
//parameter to set the attribute on the input data object for the 
//checkout operation.
ticketBO.set("claimtoken", fileName);
//The sample application uses the Flat file adapter to store the object on 
//the file system.
ticketBO.set("storetype", "FF");

//Checking the attachment out
ClaimCheckInvoker invoker = new 
 ClaimCheckInvoker("ClaimCheckIntfPartner");
//We need to pass the boolean TRUE if we want to clean up the file 
//system from the checked in object.
//If we want to keep the file on the file system, then the boolean 
//FALSE needs to be passed to the checkOut method.
DataObject checkedOut = invoker.checkOut(ticketBO, true);

//Get the attachment in the byte array format from the data object 
//returned by the service. 
byte[] checkedOutAttachmentData = checkedOut.getBytes("data");
            
//Setting the real attachment data back on the SMO.
System.out.println("Setting the checked out real attachment data 
 back on the SMO: " + checkedOutAttachmentData.toString());

attachment.setData(checkedOutAttachmentData); 

out.fire(smo); 
//Propagate the service message object to the primitive 
//that is wired to the 'out' terminal.

当消息从 ProcessOutgoingAttachment 组件传出时,它包含 SOAP 附件数据,且可被传递给 ShipmentProcessing 模块。

ShipmentProcessing 模块内的处理在本文前面已有介绍。基本上,它的工作就是将其输入数据对象的内容(特别是附件)写出到系统输出上。图 27 显示,ShipmentProcessing 模块有一个 Web 服务导出,使其能由 ProcessOutgoingAttachment 中介组件调用。

为让 ShipmentProcessing 模块写出其输入数据对象中的附件内容,对逻辑附件使用 ProcessShipmentComponentStub Java 片段。但是,同样的 Java 片段不适用于通过 ShippingWSExport 传入的物理附件。因此,如图 27 所示插入 CheckAttachment 中介组件,以写出物理附件内容。

图 27. ShipmentProcessing 模块的 Web 服务导出
ShipmentProcessing 模块的 Web 服务导出
ShipmentProcessing 模块的 Web 服务导出

样例应用程序执行说明

注意,您需要一个 WebSphere Process Server V6.2.0.1 或更高版本的测试环境来运行这部分样例应用程序。运行和测试样例应用程序最简单的方式是,使用 Process Server 测试环境,该环境可随 Integration Developer 安装。在运行和测试样例应用程序之前,您必须首先部署应用程序。

部署:

  1. 选择 Servers 视图并右键单击 Process Server 测试环境实例。
  2. 选择 Add and Remove Project 菜单项。在 Add and Remove Projects 对话框上,单击 Add All 按钮。ClaimCheckApp、OrderProcessingApp、OrderToShipmentApp 和 ShipmentProcessingApp 项目都从 Available projects 列表移到 Configured projects 列表(参见图 28)。
  3. 单击 Finish 按钮。
    图 28. 模块(项目)部署对话框
    模块(项目)部署对话框
    模块(项目)部署对话框
  4. 要启动 Process Server 测试环境实例,右键单击测试环境实例并选择 Start。等待一会儿,您就会在 Server Logs 视图中看到类似消息,如图 29 所示。
    图 29. 显示测试环境和所启动样例应用程序的服务器日志
    显示测试环境和所启动样例应用程序的服务器日志
    显示测试环境和所启动样例应用程序的服务器日志
  5. 返回到 Servers 视图并展开 WebSphere Process Server v6.2 条目,视图显示部署的模块(项目)均已启动(图 30)。
    图 30. 模块(项目)启动
    模块(项目)启动
    模块(项目)启动
  6. 在开始测试之前,确保 FlatFileAdapter 用于读写文件的文件系统上的目录存在。前面讲过,我们的样例应用程序将文件系统作为 Claim Check 数据存储使用。我们的样例应用程序需要的目录是 C:\FlatFilesAny

测试使用逻辑附件的样例应用程序

要测试使用逻辑附件的样例应用程序:

  1. 打开 OrderProcessing 模块组装图。右键单击 AddLogicalAttachmentToOrder 组件并从上下文菜单中选择 Test Component
  2. 显示 Integration Developer 测试客户端之后,可以输入一些有意义的值到 Initial request parameters 表中(图 31)。
    图 31. 指定初始请求参数的测试客户端
    指定初始请求参数的测试客户端
    指定初始请求参数的测试客户端

    注意,在 “Initial request parameters” 表中有两个高级节点(图 32)。一个节点用于 OrderIn 消息,而另一个用于 productItemIn 消息。这两个消息需要用到,且 AddLogicalAttachmentToOrder 中介组件采用 productItemIn 并使其成为 inputOrder 消息的一个逻辑附件。AddLogicalAttachmentToOrder 也将其他相关字段从 OrderIn 复制到 inputOrder。

    图 32. 初始请求参数表
    初始请求参数表
    初始请求参数表
  3. 要查看调用栈和中介消息,单击 Configuration 选项卡将 OrderToShipment 模块添加到测试会话,然后右键单击 Test configuration Default Module Test,选择 Add,然后选择 Module,如图 23 所示。
    图 33. 将 OrderToShipment 模块附着到测试会话
    将 OrderToShipment 模块附着到测试会话
    将 OrderToShipment 模块附着到测试会话
  4. 添加 OrderToShipment 模块并输入所有初始请求参数之后,单击 Continue 按钮。

检查和验证结果

当样例应用程序完成处理时,您可以看到来自客户端的所有跟踪栈和消息。

如图 34 所示,左边高亮显示的栏是调用 checkin 服务之前的调用。在右边,高亮显示的字段是逻辑附件的内容。

图 34. 调用 checkin 服务之前的附件内容
调用 checkin 服务之前的附件内容
调用 checkin 服务之前的附件内容

图 35 显示调用 checkin 服务之后的结果。如图 35 所示,productItem 被更改为包含存储附件内容和存储类型的文件名。如果您想看到文件系统中的附件内容,就需要使用 ClaimCheckInvoker.checkOut(ticketBO, false),将代码更改为在 checkout 服务之后不调用 cleanup 服务。当您再次重新运行应用程序时,可以转至 C:\FlatFilesAny,打开 ClaimCheckObject.xx.txt 来检查内容。

图 35. 调用 checkin 服务之后的附件内容
调用 checkin 服务之后的附件内容
调用 checkin 服务之后的附件内容

图 36 显示了调用 checkout 服务之前的信息,且产品说明仍然是高亮显示的文件名。

图 36. 调用 checkout 服务之前的附件内容
调用 checkout 服务之前的附件内容
调用 checkout 服务之前的附件内容

在调用 checkout 之后,Integration Test 客户端不显示进一步信息。不过,从 Server Logs 视图上,您可以看到 “Order shipped” 消息(图 37)。记得之前 “Order shipped” 消息由 ShipmentProcessing 模块中的 ProcessShipmentComponentStub 组件写到了日志文件中。

图 37. ShipmentProcessing 模块打印的消息的服务器日志
ShipmentProcessing 模块打印的消息的服务器日志
ShipmentProcessing 模块打印的消息的服务器日志

双击日志消息 <?xml version=”1.0” encoding=”UTF-8”?>,它就在 Server Logs 视图中的 “Order shipped” 消息下面。一个如图 38 所示的 Properties 对话框显示。对话框显示提供给 ShipmentProcessing 模块的数据。Properties 对话框中显示的实际数据反映您之前输入的初始请求参数。

图 38. 提供给 ShipmentProcessing 模块的数据
提供给 ShipmentProcessing 模块的数据
提供给 ShipmentProcessing 模块的数据

测试使用物理附件的样例应用程序

要测试使用 SOAP 附件的样例应用程序,您需要完成以下几个步骤:

  1. 如前面所述,部署应用程序并启动 WebSphere Process Server v6.2 测试环境实例。
  2. 在 Integration Developer 中启用 SOAP 附件特性。
  3. 在 Integration Developer 中,转至 Windows > Preferences 调出 Preferences 对话框。
  4. 在对话框左边,展开 Business integration 并单击 Integration Test Client
  5. 选中标为 Enable SOAP attachment feature 的复选框(图 39)。
    图 39. 启用用于测试的 SOAP 附件特性
    启用用于测试的 SOAP 附件特性
    启用用于测试的 SOAP 附件特性

开始测试

要开始测试:

  1. 右键单击 OrderToShipment 模块组装图中的 PrepareShipmentWS 导出组件并从上下文菜单中选择 Test Component
  2. 打开 Integration Test Client 之后,为 Web 服务消息主体部分的所有可用请求参数输入值,或导入样例应用程序提供的样例值。
  3. 要手动输入值,参考图 40,查看 Initial request parameters 表中 Web 服务消息主体的位置
    图 40. 调用 Web 服务端点的 Integration Test Client
    调用 Web 服务端点的 Integration Test Client
    调用 Web 服务端点的 Integration Test Client
  4. 除手动输入值之外,另一种方法就是使用样例应用程序提供的样例值。要导入样例值,请执行以下操作:
    • 单击 XML editor 按钮切换到 XML 编辑器(图 41)。
    • 单击左上角的 Import Message 图标。
      图 41. 将样例值导入 XML 编辑器
      将样例值导入 XML 编辑器
      将样例值导入 XML 编辑器
    • Import from File 对话框出现,显示当前工作空间的文件夹。双击 CommonLibrary 文件夹并选择 sampleInput.xml,如图 42 所示。单击 Open 按钮。
      图 42. 定位工作空间中的样例测试值
      定位工作空间中的样例测试值
      定位工作空间中的样例测试值
  5. 切换回 Value editorSwitch Editor 对话框出现时单击 Yes。您会看到 Web 服务消息主体的所有请求参数都填充有值。
  6. 要添加附件,右键单击底部的 attachments 数节点(图 43)并选择 Add Elements
    图 43. 向一个 SOAP 消息添加附件
    向一个 SOAP 消息添加附件
    向一个 SOAP 消息添加附件
  7. Add Elements 对话框中,您可以指定要添加的附件数。为方便起见,我们的测试仅使用一个附件。因此只需单击 OK(默认值为 “1”)。
  8. 接下来,单击 Type 栏并选择 text/xml,更改 attachments[0] 条目的类型为 text/xml,如图 44 所示。
    图 44. 更改附件类型
    更改附件类型
    更改附件类型
  9. 最后,指定包含附件内容的 XML 文件的路径。对于样例应用程序,我们在 CommonLibrary 模块中提供了 attachmentData.xml 文件(图 45)。
    图 45. 指定附件内容
    指定附件内容
    指定附件内容
  10. 在输入所有值之后,单击图 46 所示的 Continue 图标,开始运行测试组件。
    图 46. 调用测试组件
    调用测试组件
    调用测试组件

检查和验证结果

您可以使用 Integration Test Client 捕获的细粒度跟踪验证测试结果。注意,Integration Test Client 仅显示值编辑器中的业务对象。它 显示二进制附件。不过,我们可以在 ClaimCheckerInvoker 服务前后检查消息来验证结果。

如图 47 所示,在调用 checkin 服务之前,附件包含右边高亮显示的那些二进制附件。

图 47. 调用 checkin 服务之前的附件内容
调用 checkin 服务之前的附件内容
调用 checkin 服务之前的附件内容

图 48 显示调用 checkin 服务的结果。附件仅是一个轻量级文件名。如果您想查看文件系统中的附件内容,就需要使用 ClaimCheckInvoker.checkOut(ticketBO, false),将代码更改为在 checkout 服务之后不调用 cleanup 服务。当您再次重新运行应用程序时,可以转至 C:\FlatFilesAny,打开 ClaimCheckObject.xx.txt 来检查内容。

图 48. 调用 checkin 服务之后的附件内容
调用 checkin 服务之后的附件内容
调用 checkin 服务之后的附件内容

您可以看到,附件内容仍然是调用 checkout 服务之前的文件名,如图 49 所示。

图 49. 调用 checkout 服务之前的附件内容
调用 checkout 服务之前的附件内容
调用 checkout 服务之前的附件内容

图 50 显示,在调用 checkout 服务之后,附件内容成为原始附件数据。

图 50. 调用 checkout 服务之后的附件内容
调用 checkout 服务之后的附件内容
调用 checkout 服务之后的附件内容

结束语

本文描述了 Claim Check 模式,包括逻辑和物理 SOAP 附件。向您展示了作为 SCA 服务实现的 Claim Check 服务的样例设计和实现、一个客户端应用程序设计样例,以及通过 HTTP 和 Web Service SOAP 通信渠道使用 XML 的两个场景。您学习了如何使用自定义数据处理程序或自定义中介调用 Claim Check 服务,如何使用 Flat File 适配器存储和读取文件系统上附件的内容。

我们对样例应用程序进行了一些简化,重点介绍本文的主题:Claim Check 模式设计和实现。如果您有任何问题或您的某个用例需要建议,请随时联系作者。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=515208
ArticleTitle=使用 WebSphere Integration Developer V6.2.0.1 中的 Claim Check 模式提高应用程序效率
publish-date=09022010