整合 WebSphere ILOG JRules 與 IBM Content Manager Enterprise Edition

CloudSpace發表於2010-09-13
Alan Yaung, 高階軟體工程師, IBM

簡介: 自動決策在內容管理系統中變得越來越重要。核心應用邏輯中的外化決策邏輯能夠根據動態的業務需求管理和快速修改業務規則。IBM WebSphere ILOG JRules 是一個業務規則管理系統(BRMS),它有許多製作、部署和管理業務規則的功能,管理者可以通過它更好、更快地作出決策。IBM WebSphere ILOG JRules 和 IBM Content Manager Enterprise Edition 的整合擴大了內容管理解決方案在一個組織中更有效管理業務決策的範圍。

本文首先闡述了整合 IBM Content Manager Enterprise Edition 與 IBM WebSphere ILOG JRules 的方法。然後概述了事件框架,簡單介紹了 ILOG JRules 業務規則管理系統,本文使用一個貸款場景來說明如何開發一個定製的事件處理器從而將 ILOG JRules 整合到一個內容管理應用中。

引言

自動決策在內容管理系統中變得越來越重要。然而,對於不斷增加的用例,在一個應用中嵌入決策規則可能並不能滿足一個快速發展的業務環境的複雜需求。因此,擁有一個專門的支援業務規則建模、規則執行和規則管理的業務規則管理系統變得非常重要。

IBM WebSphere ILOG JRules 是一個業務規則管理系統(BRMS),它提供支援業務敏捷性和效率的業務規則建立、部署和管理功能。ILOG JRules 和 IBM Content Manager Enterprise Edition Version 8.4.2(下面稱為 Content Manager)的整合是基於一個事件框架的。這個整合擴充套件了 Content Manager 的功能,使之能在一個組織中實現更高效的業務決策管理。

Content Manager 支援一個事件基礎架構,它能夠整合外部應用。本文闡述瞭如何開發一個定製的事件處理器,同時該處理器是通過能與 ILOG JRules 互動的感知內容的業務邏輯驅動的。

本文概述了 Content Manager 事件框架,並介紹了 ILOG JRules 業務規則管理系統。然後使用一個示例的貸款申請場景說明如何開發一個定製的整合 ILOG JRules 和 Content Manager 的事件處理器。


認識 Content Manager 事件框架

圖 1 說明了一個支援 Content Manager 和外部應用整合的事件框架的體系結構。


圖 1. 事件框架體系結構
描述事件框架體系結構元件關係的流程圖。下面的內容解釋了它的詳細資訊。

如上圖所示,事件框架實現了 3 個主要功能:

  • 事件訂閱允許使用者確定一個專案型別和與該專案相關聯的事件。在事件訂閱過程中,事件訂閱資料儲存在 Content Manager 庫伺服器資料庫的配置表中。配置資料是通過使用 Content Manager 系統管理客戶端配置的。管理員訂閱這些事件,然後通過監控這些事件瞭解一個具體專案型別及其屬性。
  • 事件監控會在事件發生時記錄這些事件,生成事件訊息,然後訊息被髮送到一個 Java Message Service (JMS) 訊息佇列。事件監控專注於生成事件訊息。通過使用 Content Manager 的 Java® 和 C++ API 介面,應用就能夠與庫伺服器進行互動,並將生成的資料儲存到資料庫中。庫伺服器會在事件發生時根據配置記錄這些事件。所記錄的事件會被記錄到庫伺服器資料庫的一個事件佇列表中。一個事件包含事件型別、事件 ID、專案資訊和屬性資料。事件監視器能根據配置資料從事件佇列表取出事件資料,將事件轉換成 JMS 訊息,然後將 JMS 訊息放回到一個 JMS 事件佇列中。
  • 事件處理從 JMS 佇列查詢事件訊息,然後基於業務邏輯處理這些訊息。事件處理專注於事件訊息使用。事件處理器會從 JMS 佇列讀取包含事件資料的 JMS 訊息。事件處理器能夠將應用邏輯整合到 Content Manager 文件屬性中。處理整合的事件處理器是由支援 FileNet Business Process Manager 的 Content Manager 提供的,但是如果要整合其他應用,您必須開發定製的事件處理器。

認識 ILOG JRules 業務規則管理系統

自動化業務決策可以用於接受一個貸款申請以支付一個汽車保險賠付。這些決策是一個完整元素的業務操作。IBM WebSphere ILOG JRules Business Rule Management System (BRMS) 能夠使用一組面向業務分析人員、解決方案架構師和應用開發人員的工具以靈活和可預見的方式控制自動業務決策。

圖 2 說明了 ILOG JRules 的主要元件。


圖 2. ILOG JRules 概述
Rule Studio 和 Rule Team Server 相互同步。它們都部署到 Rule Execution Server。下面是它們的詳細資訊。

如上圖所示,ILOG JRules 元件分成了 3 個方面:

  • Rule Studio 是一個支援業務規則應用開發的基於 Eclipse 的整合開發環境。應用開發人員可以利用 Eclipse 整合環境開發 Java 專案和規則專案。當開發一個業務規則專案時,開發人員需要規定初始規則,設計規則模板和通過資料夾管理和組織規則。通過使用 Decision Validation Services,開發人員就能夠根據驗證和故障修復場景測試這些規則。
  • Rule Team Server 是一個基於 Web 的規則管理和授權環境,它允許業務使用者檢視、建立和修改規則。業務分析人員可以在應用開發過程中和開發完成後使用 Rule Team Server 編寫和維護業務規則。通過 Rule Studio,開發人員將規則專案釋出到 Rule Team Server,然後週期性地同步業務使用者成果和 Rule Studio 的副本。
  • Rule Execution Server 能夠讓管理員訪問他們需要監控的已部署規則集,管理決策服務和執行審計。Rule Execution Server 是一個規則執行環境(Java SE 和 Java EE),它與規則引擎互動。Rule Execution Server 具備處理管理、效能、安全性和與業務規則執行相關的日誌功能。RuleApp 是 Rule Execution Server 規定的格式。它包含了規則集,並且打包在一個 JAR 檔案中的,其中包含了執行所需要的所有東西(規則、規則流等)。規則集既可以部署在 Rule Studio 也可以部署在 Rule Team Server 上。

場景介紹

本節將介紹一個示例場景,它將說明在一個業務上下文中如何整合 ILOG JRules 和事件框架。

一個地區銀行的按揭部門計劃自動化一個貸款申請過程。這個貸款申請過程由三個工作狀態組成:SubmitLoan、Approved 和 Rejected。當一個貸款申請提交後,它會到達 SubmitLoan 操作區。如果申請獲得批准,那麼它就會轉到 Approved 操作區。如果被拒絕,它會轉到 Rejected 操作區。一個 Rejected 狀態的貸款申請可以重新提交到 SubmitLoan 操作區進行重新評估。

ILOG JRules 被整合到 SubmitLoan 操作區以實現自動決策。在貸款申請提交過程中,貸款代理人負責提供諸如貸款號、貸款數額、利率、期限等貸款資訊。當該申請到達 SubmitLoan 操作區時,這個貸款資訊就被髮送到 ILOG JRules 規則引擎進行評估。如果評估通過,這個貸款申請會自動轉移到 Approved 操作區。否則,它會被自動轉移到 Rejected 操作區。進入 Rejected 操作區的一個貸款申請可以重新傳送到 SubmitLoan 操作區。當它的貸款資訊更新後,它會被重新評估。當一個貸款申請轉到 Approved 或 Rejected 操作區時,規則引擎都會生成和傳送電子郵件通知,通知貸款申請相關人關於該筆申請的狀態。

上述具有 SubmitLoan、Approved 和 Rejected 操作區的貸款申請流程見圖 3 所示。


圖 3. 貸款申請過程
SubmitLoan 操作區之後是 Approved 或 Rejected。Rejected 的事務可以被重新提交或直接停止。Approved 事務將停止。

如圖 4 所示,我們定義了三個操作列表(SubmittedWL、ApprovedWL 和 RejectedWL),它們將監控各個操作區的工作項。


圖 4. 貸款申請過程的操作列表
截圖顯示的是一個操作列表:SubmittedWL、ApprovedWL 和 RejectedWL

Content Manager 中定義了貸款申請處理的 Loan 專案型別。 如圖 5 所示,它由以下屬性組成:

  • LoanNumber — 貸款的唯一識別符號
  • LastName — 貸款人的姓
  • FirstName — 貸款人的名字
  • CreditScore — 貸款人信用評分
  • YearlyIncome — 貸款人的年收入
  • LoanAmount — 貸款額
  • InterestRate — 貸款利率
  • Duration — 貸款期限
  • Notification — 通知接收人的電子郵件地址


圖 5. Loan 專案型別
Loan 專案型別顯示了上面列表中的每一個屬性。

Library Server Configuration 對話方塊(圖 6)中的 Enable Event Subscription 核取方塊必須選中,以便啟用一個庫伺服器例項的事件日誌功能。在專案型別級別,圖 7 顯示一個專案型別 Loan 的事件訂閱例子。這個專案型別所訂閱的事件是 Add Item 和 Update Item 事件。當管理員單擊 Event Subscription 頁面的 Add 按鈕時,頁面就會顯示一個 Define Event Subscription 對話方塊。管理員也可以選擇 General integration 選項,因為這個場景是與一個通用外部應用有關的。這個 Loan 專案型別的所有文件屬性都會被選中,以便在 Add Item 和 Update Item 事件中進行監控。


圖 6. Library Server Configuration
選中 Enable Event Sub.ion 的 Library Server Configuration 對話方塊。

圖 7. 事件訂閱
選中 Event Sub.ion 對話方塊的 General integration。

本文的重點是整合 ILOG JRules 和 Content Manager,以及一個貸款例子的業務規則。這個貸款例子來自於 IBM WebSphere ILOG JRules 資訊中心(見 參考資料 中的資訊中心連結)的“Getting started”小節。

圖 8 顯示了貸款例子所使用的兩組業務規則:

  • 合格標準
    • 最小信用評分 — 保證信用評分不小於 200。
    • 最小收入 — 保證滿足最小年收入要求。
    • 還款和信用評分對比 — 保證貸款-收入比例和信用評分都是可接受的。
  • 驗證
    • 最大貸款數額 — 保證最大貸款數額不超過 $1,000,000。

在圖中,ILOG Rule Team Server 的 Explore 選項卡中顯示了兩組規則。對於本場景,業務規則是通過 Rule Studio 釋出到 Rule Team Server 的,並且它們是以一個規則歸檔檔案(jar 格式)部署的。Rule Execution Server 是一個規則執行環境。為了簡單起見,我們選擇了 Java SE 規則會話型別,並且在一個規則會話中嵌入 Java SE 執行單元。


圖 8. ILOG JRules 業務規則
ILOG Rule Team Server 的 Explore 選項卡截圖顯示了兩組業務規則:合格標準和驗證。

圖 9 說明了一個業務規則是如何表示的。它在 Rule Team Server 的 Compose 選項卡中顯示了最小信用評分業務規則的內容。這個規則規定如果借款人的信用評分小於 200,貸款申請就會被拒絕。


圖 9. 最小信用評分
ILOG Rule Team Server 的 Compose 選擇選項卡顯示信用評分業務規則的詳細資訊。


整合體系架構

本例中使用的產品

下面是本文的例子所使用的產品:

  • IBM WebSphere ILOG JRules Version 7.0.2(試用版)
  • IBM Content Manager Enterprise Edition Version 8.4.2
  • IBM WebSphere MQ Version 6.0

本節闡述了建立貸款申請場景所使用的體系架構。這個體系架構整合了 ILOG JRules 和 Content Manager。如圖 10 所示,這個體系架構由三個部分組成:

  • 內容 — Content Manager 是內容知識庫。它的庫伺服器元件既支援貸款申請的資料建模,也支援貸款申請過程的過程建模。
  • 事件處理 — 定製的事件處理器實現了核心應用邏輯,並整合了 ILOG JRules 和 Content Manager。它從 Content Manager 接收貸款申請事件,然後將請求提交到 ILOG JRules 進行評估。它會根據評估的結果採取恰當的操作,併傳送相應的電子郵件通知。
  • 業務規則 — 業務決策邏輯是與核心應用邏輯分離的。這個業務規則是通過 ILOG JRules 規則引擎執行的。這些業務規則可以由業務分析人員使用 Rule Team Server 進行修改。


圖 10. Content Manager / ILOG 整合體系架構
圖片顯示了整合體系架構的三個部分:內容、事件處理和業務規則。

下面概括了一個貸款申請場景在整合體系架構中是如何流轉的。

  • 貸款代理人在 Content Manager 中建立一個專案型別 Loan 的貸款申請文件。
  • 當貸款申請文件建立之後,Content Manager 伺服器會自動啟動一個貸款申請過程例項。這個貸款申請會進入 SubmitLoan 操作區等待評估。
  • 管理員配置 Loan 專案型別監控文件建立和修改分別對應的一個 Add Item 事件或 Update Item 事件。因此,庫伺服器會插入一個事件資料到事件佇列表中。這個事件資料包括了諸如貸款號、貸款數額和通知等屬性。
  • 事件監視器會掃描事件佇列表查詢提交的記錄,然後查詢貸款文件的 Add Item 或 Update Item 事件。這個事件監視器能將配置資訊和從事件佇列表所查詢的事件資料轉換到一個自解釋的通用基礎事件(CBE)格式事件訊息中。然後它會將這個事件訊息傳送給 一個 Java Message Service (JMS) 佇列。
  • 有一個定製的事件處理器負責監聽 JMS 佇列,它可以從佇列查詢文件建立事件和修改事件。這個事件處理器會解析 CBE 格式的事件資料,然後將貸款資訊封裝到請求中併傳送到 ILOG JRules 規則引擎進行評估。
  • 當接收到請求時,ILOG JRules 規則引擎就會執行這些業務規則,然後返回貸款申請的評估結果。
  • 在接收到 ILOG JRules 規則引擎返回的響應後,事件處理器會將貸款申請轉發到貸款申請過程中的正確的操作區(Approved 或 Rejected),同時傳送一個電子郵件到通知列表中的接收人。

myEventHandler 定製的事件處理器的設計概述

一個定製的事件處理器的基本功能是使用 JMS 佇列中的事件訊息,然後相應地與外部應用進行互動。對於本文的場景,這個事件處理器必須連線到一個 Content Manager 伺服器,查詢事件訊息中所引用的專案的文件屬性。接下來,處理器會建立一個規則會話,然後傳送一個請求到 ILOG JRules 規則引擎,以評估貸款申請。然後這個事件處理器會使用 JavaMail API 生成傳送到接收人的電子郵件通知。

下載 示例程式,它定義了一個支援本文的場景所描述的定製的事件處理器。這個定製的事件處理器是一個名為 myEventHandler 的 JMS 應用。它使用一個非同步訊息傳送機制。它實現了一個訊息監聽器,這個監聽器可以在新訊息到達 JMS 佇列時接收這些新訊息。

清單 1 顯示了 myEventHandler 示例程式的總體結構。下面是關於這個程式功能的總體描述:

  • 這個程式匯入下面必要的程式包:
    • 用於訪問 JMS 佇列 的 JMS 和 Java Naming and Directory Interface (JNDI) 程式包
    • 用於傳送電子郵件的 JavaMail 程式包
    • 用於解析事件訊息的 SAX API 程式包
    • 用於查詢內容資料的 Content Manager API 程式包
    • 用於建立規則會話的 ILOG API 程式包
  • myEventHandler 類實現了兩個 JSM 監聽器:
    • javax.jms.MessageListener 介面的 onMessage 方法負責監聽 JMS 佇列。
    • javax.jms.ExceptionListener 介面的 onException 負責處理 JMS 異常。
  • 兩個用於解析事件訊息的內部類:
    • myContentHandler 類擴充套件了 SAX API 的 DefaultHandler 類,它負責解析事件訊息。
    • myErrorHandler 類實現了 SAX API 的 ErrorHandler 介面。
  • 函式 sendMail 負責建立電子郵件並使用 JavaMail API 將通知傳送給接收者。它是在接收到一個事件訊息時由函式 onMessage 呼叫的。
  • 函式 executeILOGRules 將一個請求傳送到 ILOG JRules 規則引擎再執行規則。這個規則引擎會評估貸款申請,然後返回響應給呼叫者。
  • myEventHandler 類初始化時,函式 waitForQUIT 就會被呼叫。它會提示使用者執行 quit 命令。當接收到一個 quit 命令時,myEventHandler 類就會退出。


清單 1. 程式結構

				
// JMS API
import javax.jms.*;
// JNDI API
import javax.naming.*;
// Java IO and utility
import java.io.*;
import java.util.*;
// SAX abd XML parsing
import org.xml.sax.*;
import org.xml.sax.helpers.*;
// JavaMail API
import javax.mail.*;
import javax.mail.internet.*;
// CM API
import com.ibm.mm.sdk.server.*;
import com.ibm.mm.sdk.common.*;
// ILOG API
import ilog.rules.res.session.*;
import ilog.rules.res.model.*;
import ilog.rules.res.session.ruleset.*;

public class myEventHandler extends Thread 
             implements javax.jms.MessageListener, javax.jms.ExceptionListener
{

    static class myContentHandler extends DefaultHandler
    {
        // methods in the myContentHandler class
    }
    
    static class myErrorHandler implements ErrorHandler
    {
        // methods in the myErrorHandler
    }   
            
    public void run() 
    {      
        this.waitForQUIT();       
    }
    
    private void waitForQUIT() throws Throwable
    {
        // prompt for the QUIT command to exit     
    }     
    
    public myEventHandler(String database, String userid, String pw) throws Throwable
    { 
        // set up JMS connection
        // initialize SAX parser  
        // start the thread for waiting the QUIT command to exit   
    }
    
    public static void main(String[] argv)
    {
        // start the myEventHandler instance
        myEventHandler eh = new myEventHandler(argv[0], argv[1], argv[2]);
    }
    
    public void onMessage(javax.jms.Message message) 
    { 
        // listen to the JMS queue
        // retrieve a JMS message 
        // parse the JMS message to obtain the event data
        // process the event data
        // compose an e-mail
        // call the sendMail function to send out an e-mail notification
    }  

    public void onException(JMSException exc)
    {
        // print the error message when a JMS exception occurs 
    }

    public void sendMail(String mailhost, String from, String[] to, 
                        String subject, String text) 
    {
        // send an e-mail notification to the claim reviewers
    }
    
    public IlrSessionResponse executeILOGRules(String firstName,
                String lastName, int loanAmount, int duration, 
                float interestRate, int creditScore, int yearlyIncome)
    {
        // send a request to ILOG JRules rule engine for rule execution
        // an IlrSessionResponse object is returned with the evaluation result
    }
}            

文章的下面幾個小節更詳細地檢查了示例的一些主要部分:

  • 連線一個 JMS 佇列
  • 查詢一個事件訊息中的事件資料
  • 解析一個事件訊息中的事件資料
  • 從一個 Content Manager 伺服器查詢事件所引用的內容資料
  • 執行規則
  • 移動過程中的貸款申請
  • 傳送電子郵件給通知接收者

連線一個 JMS 佇列

清單 2 顯示了 myEventHandler 示例程式中與一個 JMS 佇列建立連線的一部分程式碼。

首先,這個程式通過查詢上下文物件獲得一個指定名稱的佇列連線工廠。其次,它在佇列連線中建立一個佇列會話,並通過查詢上下文物件獲得一個指定名稱的佇列。然後它會為一個特定的佇列建立一個作為訊息接收的佇列接收器。這個佇列接收器會使用一個訊息選擇器 APPLICATION = 'none' 來監聽佇列,這表示資料來自於一般整合。JMS 佇列中只有那些帶有訊息屬性 APPLICATION 且屬性值為 'none' 的訊息會被查詢到。

當佇列接收器建立後,這個程式會在佇列接收器中建立訊息監聽器。而異常監聽器則是在佇列連線中建立。在開始連線 JMS 之前,這個程式會執行另外兩個任務:

  • 初始化用於解析事件訊息的 SAX 解析器
  • 連線 Content Manager 以查詢內容資料

最後一步是啟動 JMS 連線。在 JMS 連線建立後,onMessage 訊息監聽器和 onException 異常監聽器可以接收來自於 JMS 佇列的輸入訊息。


清單 2. 連線到一個 JMS 佇列

				
        // obtain the queue connection factory
        factory = (QueueConnectionFactory)ctx.lookup(_qcf_name);
        // create a queue connection
        connection = factory.createQueueConnection();
        System.out.println("Queue connection created");
        // create a queue session
        qSession = connection.createQueueSession(false, 
                                                 javax.jms.Session.AUTO_ACKNOWLEDGE);
        System.out.println("Queue session created");
        // create a queue
        testQueue = (javax.jms.Queue)ctx.lookup(_queue_name);
        System.out.println("Queue = [" + _queue_name + "]");
        // create a consumer listening to the specified queue 
        // for message property APPLICATION = 'none' (general integration)
        qReceiver = (QueueReceiver)qSession.createConsumer(testQueue, 
                                                           "APPLICATION = 'none'");
        // set the message listener
        qReceiver.setMessageListener(this);
        // set the exception listener        
        connection.setExceptionListener(this);

        // initialize the SAX parser
        try {
            _parser = initParser(_dh);          
        } catch (SAXException se) {
            System.out.println("SAXException - " + se.getMessage());
            throw se;
        }
        
        // connect to the Content Manager
        dsICM = new DKDatastoreICM();
        dsICM.connect(database, userid, pw, "");
        System.out.println("datastore connected.");        
                
        // start the JMS connection
        connection.start();       
        System.out.println("Queue connection started");        


查詢事件資料

在 JMS 連線啟動後,onMessage 訊息監聽器就能夠以先進/先出的方式從 JMS 佇列查詢訊息。一個 JMS 訊息首先會被強制轉換成一個 TextMessage 物件。

清單 3 顯示了 myEventHandler 示例程式中用於查詢事件資料的一部分程式。這個程式能夠從 TextMessage 物件查詢到訊息字串以及下面六個訊息屬性:

  • DATABASE 是生成事件的 Content Manager 伺服器名。
  • TYPE 是事件的型別(例如,"item-create")。
  • LAUNCH 表示這個訊息是否請求執行一個工作流。這個屬性的值可能是 "true""false"。對於一般整合,這個值是 "false"
  • ID 是事件的識別符號(例如, "A1001001A10B19B12751I284680000000000000000225000")。
  • APPLICATION 是與一個工作流執行相關的應用。對於與 FileNet Business Process Manager (BPM) 整合的過程,這個值是 "BPM"。對於一般整合,這個值是 "none"
  • COUNT 表示事件中包含了多少資料元素。如果事件的長度小於或等於 1024,那麼事件中只有一個上下文資料元素。否則,如果計數大於 1,那麼定製的事件處理器需要將多個上下文資料元素連線在一起。

接下來,這個程式會解析訊息字串,這個字串是用一種通用基礎事件(CBE)格式表示的。下面是用於將 CBD 格式化的訊息字串的資訊傳遞到程式的變數:

  • strGlobalInstanceId 是事件的全域性例項 ID,(例如, "A1001001A10B19B12751I284680000000000000000225000",就是相同的訊息 ID)。
  • strReturnMsg 包含了來自於 Content Manager 內容知識庫的事件資料。
  • strReturnTime 是 GMT 表示的事件建立時間(例如, "2010-03-19T01:03:11.256Z")。
  • strApplication 是生成事件的應用名稱(例如,"Content Manager Event Monitor").
  • strComponent 是生成事件的元件名稱(例如,"Content Manager 8.4.02.000")。
  • strExecutionEnvironment 表示執行環境的作業系統和架構(例如,"Windows XP[x86]")。
  • strLocation 是事件監視器的主機名和 IP 地址(例如,"myhost/1.11.22.33")。
  • strSubComponent 是子元件的名稱(例如,"Event Monitor")。


清單 3. 查詢事件資料

				
            // cast the message to the TextMessage object
            msg = (TextMessage) message;
            // retrieve the raw string from a JMS message
            rawString = msg.getText();

            System.out.println("Reading message: " + rawString);
        
            // retrieve the message properties from a JMS message
            msgDatabase = msg.getStringProperty("DATABASE");
            msgType = msg.getStringProperty("TYPE");
            msgLaunch = msg.getStringProperty("LAUNCH");
            msgID = msg.getStringProperty("ID");
            msgApplication = msg.getStringProperty("APPLICATION");
            msgCount = msg.getStringProperty("COUNT");
        
            // create an input source from the raw string
            ByteArrayInputStream bais = new ByteArrayInputStream
                                        (rawString.getBytes("UTF-8"));
            InputSource is = new InputSource(bais);
            bais.close();
            
            // parse the string
            try {
              _parser.parse(is);
            } catch (SAXParseException se) {
              System.out.println("Encountered a SAX parser error" 
                                 + " - " + se.getMessage());
              se.printStackTrace();
              throw se;
            }
            
            // retrieve the information from a CBE-formatted string
            strGlobalInstanceId = ((myContentHandler)_dh).getGlobalInstanceId();
            strReturnMsg = ((myContentHandler)_dh).getReturnMsg();
            strReturnTime = ((myContentHandler)_dh).getReturnTime();
            strApplication = ((myContentHandler)_dh).getApplication();
            strComponent = ((myContentHandler)_dh).getComponent();
            strExecutionEnvironment = ((myContentHandler)_dh).getExecutionEnvironment();
            strLocation = ((myContentHandler)_dh).getLocation();
            strSubComponent = ((myContentHandler)_dh).getSubComponent();
			


解析事件資料

清單 4 顯示了 myEventHandler 程式中解析從訊息字串查詢的事件資料的一部分程式。這些程式碼能從事件資料獲取 PID 字串和 ITEMTYPE 名稱。PID 字串和 ITEMTYPE 名稱在後面會用於查詢內容資料和建立電子郵件通知。

StringTokenizer 物件是使用事件資料和分隔符 ";" 例項化的。其中,一個 while 迴圈會遍歷所有識別符號,如果遇到 "ICMEMEND" 或遍歷完所有識別符號時,迴圈結束。每一個識別符號都是用一個 3 元組元素 = 表示的。帶有 ITEMTYPE 標籤的識別符號包含了事件資料所引用的文件的持久化 ID 字串。


清單 4. 解析事件資料

				
            // Use the StringTokenizer to parse the event message           
            StringTokenizer tokenizer = new StringTokenizer(strReturnMsg, ";");
 
            // variable for PID
            String pid = "";
            // variable for itemtype
            String itemtype = "";
             
            String strPart = ""; 
            int pos = 0;
            String tagPart = "";
            
            // retrieve pid and itemtype from the event message
            while (true) {
              strPart = tokenizer.nextToken();
              if (strPart.equalsIgnoreCase("ICMEMEND")
                  || strPart == null || strPart.equals("")) break;

              pos = strPart.indexOf('=');
              tagPart = "";
 
              if (pos > 0) {      
                  tagPart = strPart.substring(0, pos);
              }
              else continue;
 
              if (tagPart.equalsIgnoreCase("ITEMTYPE")) {
                  pos = strPart.indexOf('=');
 
                  if (pos > 0) {
                      itemtype = strPart.substring(pos + 1);
                  }
              }
              else {
                if (tagPart.equalsIgnoreCase("PID")) {
                    pos = strPart.indexOf('=');
 
                    if (pos > 0) {
                        pid = strPart.substring(pos + 1);
                    }
                }
              }
            } // end while
			


查詢內容資料

通過指定從事件資料查詢到的 PID 字串,我們就能從 Content Manager 知識庫中查詢到文件後設資料庫。清單 5 顯示了 myEventHandler 示例程式中從一個 Content Manager 伺服器查詢一個動態資料物件(DDO 物件)及其屬性的一部分程式碼。一個查詢呼叫能夠為 DDO 物件填充它的屬性值。

然後,下面這些屬性會被查詢到:

  • InterestRate 是貸款利率(例如,"0.05")。
  • FirstName 是貸款人的名字。
  • LastName 是貸款人的姓。
  • LoanAmount 是貸款數額(例如,"500000")。
  • Duration 是以月為單位的貸款期限。
  • CreditScore 是申請人的信用評分(例如,"310")。
  • YearlyIncome 是申請人的年收入。
  • Notification 是包含一組電子郵件地址的子元件,它有一個記錄接收者電子郵件的屬性 EMailAddress(例如,"user@host.com")。

DDO 物件的屬性值在後面將用於建立一個電子郵件通知。


清單 5. 查詢內容資料

				
            // retrieve the DDO object with the pid string
            DKDDO ddo  = (DKDDO)dsICM.createDDO(pid);	        
            ddo.retrieve();
            // retrieve the LoanNumber attribute
            short dataId = (short)ddo.dataId("LoanNumber");              
            String loanId = (String)ddo.getData(dataId);
            // retrieve the InterestRate attribute
            dataId = (short)ddo.dataId("InterestRate");                
            float interestRate = ((java.math.BigDecimal)
                                 (ddo.getData(dataId))).floatValue();
            // retrieve the FirstName attribute
            dataId = (short)ddo.dataId("FirstName");              
            String firstName = (String)ddo.getData(dataId);
            // retrieve the LastName attribute
            dataId = (short)ddo.dataId("LastName");              
            String lastName = (String)ddo.getData(dataId);           
            // retrieve the LoanAmount attribute
            dataId = (short)ddo.dataId("LoanAmount");   
            int loanAmount = ((Integer)(ddo.getData(dataId))).intValue();
            // retrieve the Duration attribute
            dataId = (short)ddo.dataId("Duration");   
            short duration = ((Short)(ddo.getData(dataId))).shortValue();
            // retrieve the CreditScore attribute
            dataId = (short)ddo.dataId("CreditScore");   
            short creditScore = ((Short)(ddo.getData(dataId))).shortValue();
            // retrieve the YearlyIncome attribute
            dataId = (short)ddo.dataId("YearlyIncome");   
            int yearlyIncome = ((Integer)(ddo.getData(dataId))).intValue();
            // retrieve the Notification component
            DKChildCollection notification = (DKChildCollection) ddo.getData(
                     (short)ddo.dataId(DKConstant.DK_CM_NAMESPACE_CHILD, 
                     "Notification"));
            dkIterator iterNotification = notification.createIterator();
            int count = notification.cardinality();
            // variable for Notification
            String[] notificationList = new String[count];
            int index = -1;
            // construct the array of e-mail addresses
            while (iterNotification.more()) {
              DKDDO ddoEmail = (DKDDO) iterNotification.next();
              ddoEmail.retrieve();
              dataId = (short) ddoEmail.dataId("EMailAddress");
              String email = (String) ddoEmail.getData(dataId);
              if (email == null || email.trim().equals("")) continue;
              else {
                  index++;              
                  notificationList[index] = email.trim();
              }
            } 


執行規則

因為整合體系結構將決策交由一個 ILOG JRules 規則引擎執行,這個定製的事件處理器將用於建立一個 ILOG JRules 連線會話。接著,貸款資訊會被傳遞到規則引擎進行評估。然後評估響應會返回給定製的事件處理器以便執行更進一步處理。

清單 6 顯示了 myEventHandler 示例程式中包含執行規則的詳細步驟的一部分程式碼。總而言之,這部分程式碼執行了以下操作:

  • 建立一個示例程式使用的 J2SE 規則會話。
  • 建立一個允許事件處理器設計規則路徑和輸入引數的會話請求。
  • 在請求中根據以下語法設定規則路徑: "/{RuleApp name}[/{version}]/{ruleset name}[/{version}]"
  • 在請求中設定 borrowerloan 輸入引數。
  • 傳送請求到 ILOG JRules 規則引擎中執行,然後返回一個包含評估響應的 IlrSessionResponse 物件。


清單 6. 執行規則

				
        // create a J2SE session 
        IlrSessionFactory factory = new IlrJ2SESessionFactory();
        IlrStatelessSession session = factory.createStatelessSession();
        // create a session request
        IlrSessionRequest sessionRequest = factory.createRequest();
        
        //  The rule path is composed of: 
        //      /{RuleApp name}[/{version}]/{ruleset name}[/{version}]
        //
        //  Note that the rule archive is deployed in the file system 
        //  under the res_data subdirectory.
        String rulesetpath = "/miniloanruleapp/1.0/miniloanrules/1.0";

        sessionRequest.setRulesetPath(IlrPath.parsePath(rulesetpath));

        // ensure correct version of the ruleset is taken in account
        sessionRequest.setForceUptodate(true);
        sessionRequest.setTraceEnabled(true);
        sessionRequest.getTraceFilter().setInfoAllFilters(true);

        // set the input parameters for the execution of the rules
        Map inputParameters = new HashMap ();
       
        // miniloan.Borrower borrower = new miniloan.Borrower("Tom", 500, 50000);
        // This expression sets the input parameter to a borrower named Tom
        // with a credit score of 500 and yearly income of 50000.
        miniloan.Borrower borrower = new miniloan.Borrower(lastName+", "+firstName, 
                                                           creditScore, yearlyIncome);

        // miniloan.Loan loan = new miniloan.Loan(500000, 240, 0.05);
        // This expression creates a new loan with an amount of 500000,
        // a duration of 240 months, and an interest rate of 5%.
        miniloan.Loan loan = new miniloan.Loan(loanAmount, duration, interestRate);

        inputParameters.put("borrower", borrower);
        inputParameters.put("loan", loan);

        sessionRequest.setInputParameters(inputParameters);
        // execute the rules
        IlrSessionResponse sessionResponse = session.execute(sessionRequest);
        return sessionResponse;    


在過程中移動貸款申請

清單 7 顯示了 myEventHandler 示例程式中選擇貸款過程中將貸款申請從 SubmitLoan 操作區向前移動的正確路徑的一部分程式碼。如果貸款被批准,它會從 SubmitLoan 操作區移動到 Approved 操作區。如果貸款被拒絕了,它會從 SubmitLoan 操作區移動到 Rejected 操作區。


清單 7. 繼續處理貸款申請

				
            // Locate the workpackage referenced by the pid string
            String[] wpList = drICM.listWorkPackagePidStringsWithItem(pid);
            for (int i = 0; i < wpList.length; i++)
            {
                if ((drICM.retrieveWorkPackage(wpList[i], true))
                    .getWorkNodeName().equalsIgnoreCase("SubmitLoan"))
                {
                  if (approved) {
                     // Advance the workpackage to the "Approved" work basket, 
                     // if the workpackage is located at the "SubmitLoan" work basket 
                     // and approved = true.
                     drICM.continueProcess(wpList[i], "Approve", "ICMADMIN");
                  }
                  else
                  {
                     // Advance the workpackage to the "Rejected" work basket, 
                     // if the workpackage is located at the "SubmitLoan" work basket 
                     // and approved = false.
                     drICM.continueProcess(wpList[i], "Reject", "ICMADMIN");
                  }                 
                  ...
                }
                ...                 
            }


傳送電子郵件通知

清單 8 顯示了 myEventHandler 示例程式中使用 JavaMail API 通過簡單郵件傳輸協議(SMTP)傳送電子郵件的一部分程式碼,並顯示了程式 sendMail 函式。首先,要指定一個 SMTP 伺服器名,並例項化一個會話物件。其次,設定發件人地址和收件人地址陣列。這個程式還設定了電子郵件標題、郵件程式和傳送日期。最後,程式呼叫函式 Transport.send 將電子郵件傳送到指定的 SMTP 伺服器,由伺服器將電子郵件傳送給接收者。


清單 8. 傳送電子郵件通知

				
        Properties props = System.getProperties();
        
        // use SMTP 
        if (mailhost != null) props.put("mail.smtp.host", mailhost);

        // get a Session object
        javax.mail.Session session = javax.mail.Session.getInstance(props, null);
        if (debug) session.setDebug(true);

        // construct the message
        javax.mail.Message msg = new MimeMessage(session);
        // set From address 
        if (from != null)
            msg.setFrom(new InternetAddress(from));
        else
            msg.setFrom();
        
        InternetAddress[] toAddresses = new InternetAddress[to.length];
        for (int i = 0; i < to.length; i++) {
            toAddresses[i] = new InternetAddress(to[i]);
        }
        // set To address
        msg.setRecipients(javax.mail.Message.RecipientType.TO, toAddresses);
        
        // optional
        if (cc != null)
            msg.setRecipients(javax.mail.Message.RecipientType.CC, 
                              InternetAddress.parse(cc, false));
        if (bcc != null)
            msg.setRecipients(javax.mail.Message.RecipientType.BCC, 
                              InternetAddress.parse(bcc, false));
        // set Subject 
        msg.setSubject(subject);
        // set e-mail text
        msg.setText(text);

        msg.setHeader("X-Mailer", mailer);
        msg.setSentDate(new Date());
        // send out the e-mail
        Transport.send(msg);


瀏覽示例貸款申請

本節將通過循序漸進的方式介紹一個特定貸款申請例子來演示示例程式的功能,以及 Content Manager 和 ILOG 之間的整合。

這個例子是從一位貸款代理人建立一個貸款申請文件開始的。文件的建立觸發了一個專案建立事件,它通過一個 JMS 佇列從事件監聽器流到定製的事件處理器。如圖 11 所示,這個定製的事件處理器會通過 ILOG JRules 規則引擎決定是否要批准或拒絕這個貸款申請,然後這個事件處理器會根據它被批准或拒絕來繼續在貸款過程中流轉這個貸款申請,並且傳送恰當的電子郵件通知給接收者。


圖 11. 貸款場景
圖片描述通過 Content Manager / ILOG 整合架構實現的事件流轉。

當貸款代理人為他的客戶提交了一個貸款申請後,這個提交操作會自動建立一個事件,這個事件會觸發定製的事件處理器來處理這個申請。圖 12 描述一個完整的輸入介面,其中貸款代理人可以輸入以下資訊:

  • 貸款號: 01-234-5678-8
  • 姓: Doe
  • 名: John
  • 信用評分: 310
  • 年收入: 30000
  • 貸款數額: 500000
  • 利率: 0.05
  • 期限: 240
  • 通知: user@host.com


圖 12. 貸款申請資訊
填寫了上面所示的資料的貸款申請輸入介面。

在這個特殊的案例中,根據 ILOG JRules 規則引擎的評估響應,這個貸款申請被拒絕了,因為:

  • 與信用評分相比,債務-收入太高
  • 債務-收入比例太大

結果,定製的事件處理器會將貸款申請從 SubmitLoan 操作區移到 Rejected 操作區。圖 13 顯示 RejectedWL 工作列表現在包含了這個貸款的貸款申請資訊。


圖 13. RejectedWL 工作列表
RejectedWL 截圖。工作列表包含了貸款號為 01-234-5678-8 的示例貸款申請。

圖 14 是一個事件通知例子,在這裡它是由定製的事件處理器傳送的電子郵件。這個事件通知包含了下面的資訊:

  • 事件資訊,如主機名、資料庫、事件型別、訊息 ID 和專案型別
  • 貸款資訊,如貸款號、姓、名、信用評分、年收入、貸款數額、利率和期限
  • 帶有評估詳細資訊的審批狀態


圖 14. 電子郵件通知
由事件處理器生成的一個示例電子郵件截圖。


結束語

IBM Content Manager Enterprise Edition 支援能整合外部應用的事件基礎架構。本文描述了一個場景和一個定製的事件處理器的設計,這個定製的事件處理器整合了 IBM WebSphere ILOG JRules 和 Content Manager。在 下載 小節中提供的示例程式碼演示了 Content Manager 和 ILOG JRules 之間通過定製的事件處理器實現的互動。通過在快速變化環境中管理業務規則的功能,解決方案開發人員能夠在企業內容管理領域開發更高效的業務應用。

原文連結:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-1005ilogjrulescontentmanager/index.html

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

相關文章