博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Integration Developer中的Claim Check模式提高应用程序效率(一)
阅读量:2492 次
发布时间:2019-05-11

本文共 19269 字,大约阅读时间需要 64 分钟。

, 软件工程师, IBM
Eugene Kharlamov 的照片
Eugene Kharlamov 是位于加拿大安大略省的 IBM 多伦多实验室的软件工程师。他为 WebSphere Integration Developer 开发连接性组件配置工具。
, 高级 IT 架构师, IBM
作者照片
Brian Petrini 是 (ISSW) 的一名集成架构师和顾问。他在 WebSphere Process Server、WebSphere Enterprise Service Bus、WebSphere Adapters 和 WebSphere InterChange Server 方面有很深的造诣。他自 1999 年以来一直致力于集成产品的客户实现,并且经常撰写和发表最佳实践方面的文章。他的专业是电子与计算机工程。
, 高级技术人员, IBM
Janette Wong
Janette Wong 是一名高级技术人员。在过去几年中,Janette 一直在推进业务流程管理(BPM)领域的模式工作。她带领收集该领域的初始需求,为改进模式理念和文档做出了贡献,并带领该模式的后续推进工作。
, 软件开发人员, IBM
Shu Tan 的照片
Shu Tan 是 IBM 加拿大实验室的软件开发人员。Shu 开发过很多被添加到 WebSphere Integration Developer 中的特性。她是 WebSphere Integration Developer 中的附件支持的核心开发人员。

简介: 本文描述 Claim Check 模式,并向您展示如何在 Service Component Architectur 上下文中使用该模式。一个样例应用程序向您展示如何使用 WebSphere® Integration Developer V6.2.0.1 实现模式并在 WebSphere Process Server V6.2.0.1 或更高版本上运行它。

为使应用程序高效运行,您不希望它携带多余数据 —— 应用程序不需要的数据。携带过多的数据有一些负面影响,这包括增加的内存使用率、数据模型的紧耦合,以及 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” 之后,不一定会立即从数据存储中删除它。

Claim Check 模式解决方案

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

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

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

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

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

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

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

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

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

Process Server 和 WebSphere ESB 拥有显式功能来处理附件,如 一文所述。但是,仅仅因为您可以做某件事情,并不代表您应该去做。

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

最关键的问题是:

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

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

Claim Check 模式解决方案

阐释了逻辑和物理附件的处理。它包含 4 个模块:

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

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

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

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

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

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

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

逻辑附件的 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) 附件的签入和签出。

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

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

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

ClaimCheck 模块组装图

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

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

Claim Check 服务接口

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

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

包装附件的 ClaimCheckObject

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

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

包装索取令牌的 TicketEnvelope

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

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

Claim Check 服务 checkin 操作的请求流

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

Claim Check 服务 checkin 操作的响应流
Claim Check 服务 checkout 操作的响应流

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

FlatFileStore EIS 导入组件配置

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

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

FlatFileImport1 接口

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

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

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

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}
public DataObject checkIn(DataObject attachment, String storetype) |-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error:  The previous line is longer than the max of 90 characters ---------|{	//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;      }   	return				null;}

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

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

public DataObject checkOut(DataObject ticket, boolean performCleanup)|-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error:  The previous line is longer than the max of 90 characters ---------|{	//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 utput = ((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;        }    }    return				null;}

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

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

OrderProcessing 模块组装图

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

OrderPrepareInterface 接口

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

OrdersInterface 接口
AddLogicalAttachmentToOrder 内的转换

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

OrderProcessing 模块的 HTTP 导入

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

逻辑附件的 OrderToShipment 组装图

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

自定义数据处理程序配置 CheckinConfiguration
CheckinConfiguration 属性

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

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

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

public Object transform(Object incomingSourceStream, Class |-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error:  The previous line is longer than the max of 90 characters ---------|	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;   	}

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

CreateShipment 内的转换

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

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

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

CheckoutConfiguration 属性

CheckoutConfiguration 中包含的属性是:

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

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

public				void 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,该组件将数据对象的内容写到系统输出上。

ShipmentProcessing 模块的 HTTP 导出

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

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-673750/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14789789/viewspace-673750/

你可能感兴趣的文章