使用Integration Developer中的Claim Check模式提高應用程式效率(一)

CloudSpace發表於2010-09-13
Eugene Kharlamov, 軟體工程師, IBM
Brian M. Petrini, 高階 IT 架構師, IBM
Janette Wong, 高階技術人員, IBM
Shu Tan, 軟體開發人員, IBM

簡介: 本文描述 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” 之後,不一定會立即從資料儲存中刪除它。


圖 1. 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 模式且何時使用它。畢竟,在使用 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 模式解決方案

樣例應用程式 闡釋了邏輯和物理附件的處理。它包含 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 模式解決方案

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 模式解決方案

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 作為一個名為 “ClaimCheck” 的 SCA 模組予以實現。它使用一個名為 ClaimCheckExport 的 SCA 匯出作為入口點,如圖 4 所示。


圖 4. ClaimCheck 模組組裝圖
ClaimCheck 模組組裝圖

圖 5 顯示,ClaimCheckExport 通過三個操作將 ClaimCheckIntf 介面公開給客戶端:

  • checkin:該操作由客戶端呼叫,用於簽入一個附件。它接受 ClaimCheckObject 型別的一個物件,該物件將附件包裝為一個輸入,並在 TicketEnvelope 型別的資料物件中返回一個索取令牌。
  • checkout:該操作用於簽出一個附件。它接受 TicketEnvelope 型別的資料物件中的索取令牌,並返回包轉附件的 ClaimCheckObject 型別的 Claim Check 資料物件。
  • cleanup:該操作用於儲存維護。簽出附件之後,使用者可能希望清理儲存,除非出於除錯或其他原因而需要永久儲存附件。清除操作接受 TicketEnvelope 型別的資料物件中的索取令牌來定位並從儲存中刪除附件內容。


圖 5. 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 操作的請求流

中介元件 ClaimCheckAdapterMapper 的請求流實現對於 checkin 和 checkout 操作是類似的(參見圖 9 和圖 10)。請求流包括平面檔案介面 FlatFileImport1 和憑證索取服務介面 ClaimCheckIntf 使用的業務物件的轉換。cleanup 操作是一種單向操作,因而沒有響應流。


圖 9. Claim Check 服務 checkin 操作的響應流
Claim Check 服務 checkin 操作的響應流

圖 10. 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 使用特定介面卡生成的介面 FlatFileImport1(見圖 12)。在 FlatFileImport1 介面定義的操作與 ClaimCheckIntf 介面定義的操作之間有一個一對一的對映(參見 圖 5)。檔名由 FlatFileImport1 介面的 Create 操作自動返回。然後樣例應用程式將該檔名用作一個索取令牌,用於簽出附件。

retrieveFlatFile 操作將包裝在 FlatFile 資料物件中的檔名作為輸出,然後返回在輸出目錄中找到的給定名稱的檔案(參見圖 11 中的 “Output directory” 欄位)。deleteFlatFile 操作也將包裝在 FlatFile 資料物件中的檔名作為輸出,然後從輸出目錄中刪除給定名稱的檔案。


圖 12. 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) 
|-------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。從資料處理程式(圖 2)和自定義中介原語(圖 3)呼叫了同樣的方法。該方法也接受一個 boolean 輸入引數,指明簽出附件之後是否需要清理儲存。它使用引用夥伴名定位 Claim Check 服務,呼叫 Claim Check 服務上的 checkout 方法,從 Claim Check 服務返回的物件上提取附件,根據需要清理儲存,最後將附件返回給呼叫方。

清單 3 顯示了簽出附件的 checkout 方法。參考 下載 部分中的專案交換檔案,檢視另一個 checkout 方法的程式碼。


清單 3. 附件的 ClaimCheckInvoker 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 所示。


圖 13. OrderProcessing 模組組裝圖
OrderProcessing 模組組裝圖

AddLogicalAttachmentToOrder 中介元件使用一個單向操作實現 OrderPrepareInterface 介面,該操作接受兩個輸入引數:GenericOrder 型別的 OrderInProductItem 型別的 ProductItemIn(圖 14)。


圖 14. OrderPrepareInterface 介面
OrderPrepareInterface 介面

AddLogicalAttachmentToOrder 中介使用一個 XSL 轉換將 ProductItemIn 資料物件作為邏輯附件附著到 OrdersInterfaceOrder 型別的 inputOrder 資料物件(見圖 15)。圖 16 顯示了 XSL 轉換。注意,除了在 inputOrder 資料物件中建立邏輯附件之外,orderIn 資料物件中的其他欄位,比如 idamount,也被複制到 inputOrder 資料物件。


圖 15. OrdersInterface 介面
OrdersInterface 介面

圖 16. AddLogicalAttachmentToOrder 內的轉換
AddLogicalAttachmentToOrder 內的轉換

帶有附件的 inputOrder 資料物件建立好之後,它被傳遞給 HTTP 匯入繫結元件 ProcessOrder(圖 17)。對繫結元件進行配置以呼叫 OrderToShipment 模組。


圖 17. OrderProcessing 模組的 HTTP 匯入
OrderProcessing 模組的 HTTP 匯入

請求到達 OrderToShipment 模組的 HTTP 匯出繫結元件 ProcessOrderService(圖 18)。


圖 18. 邏輯附件的 OrderToShipment 組裝圖
邏輯附件的 OrderToShipment 組裝圖

ProcessOrderService 匯出被配置為使用自定義資料處理程式配置 CheckinConfiguration(圖 19),而後者反過來被配置為呼叫自定義資料處理程式 ClaimCheckDataHandler(圖 20)。


圖 19. 自定義資料處理程式配置 CheckinConfiguration
自定義資料處理程式配置 CheckinConfiguration

圖 20. 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 
|-------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;
   	}

參考上面 圖 3,資料處理程式的 transform 方法返回後,更新的 inputOrder 資料物件(邏輯附件被索取令牌替換)被傳遞給 CreateShipment 中介元件。該中介元件將 inputOrder 資料物件轉換成(ShipmentRequisition 型別的)inputShipmentInfo 資料物件。注意,索取令牌從 inputOrder 源資料物件的 productItem 元素移到 inputShipmentInfo 目標資料物件的 productDescription 元素(圖 21)。


圖 21. CreateShipment 內的轉換
CreateShipment 內的轉換

CreateShipment 中介元件完成轉換之後,ProcessShipment HTTP 匯入繫結元件被呼叫(圖 22)。這個匯入繫結元件被配置為傳送一個 XML 格式的 HTTP POST 請求到目標 ShipmentProcessing 模組。另外,繫結元件被設定為使用自定義資料處理程式配置 CheckoutConfiguration。


圖 22. 自定義資料處理程式配置 CheckoutConfiguration
自定義資料處理程式配置 CheckoutConfiguration

與前面描述的 CheckinConfiguration 類似,CheckoutConfiguration 包含大量由自定義資料處理程式使用的屬性。不過,這種情況是發生在 Claim Check 服務簽出附件的過程中。


圖 23. 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 方法

				
				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,該元件將資料物件的內容寫到系統輸出上。


圖 24. ShipmentProcessing 模組的 HTTP 匯出
ShipmentProcessing 模組的 HTTP 匯出

上面內容詳細描述了處理邏輯附件所用的 Claim Check 模式解決方案的樣例實現。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-673750/,如需轉載,請註明出處,否則將追究法律責任。

相關文章