使用WEBLOGIC PORTAL規則引擎中實現動態業務邏輯

發表于:2007-06-22來源:作者:點擊數: 標簽:
簡介 業務應用的 需求 總是隨著業務環境的變化趨勢而不斷地改變。決策很少是一成不變的,并且競爭壓力要求業務邏輯的設計和實現具有靈活性,以快速地適應不斷變化的需求。 通常,對業務邏輯的更改必須由 開發 人員來完成,然后進行多次徹底的 測試 ,而這將

   

  簡介

  業務應用的需求總是隨著業務環境的變化趨勢而不斷地改變。決策很少是一成不變的,并且競爭壓力要求業務邏輯的設計和實現具有靈活性,以快速地適應不斷變化的需求。

通常,對業務邏輯的更改必須由開發人員來完成,然后進行多次徹底的測試,而這將是一個很耗時的過程。在應用程序的修改工作完成后,需要將其重新部署到服務器,需要留出預定的停機時間,以防應用程序對用戶不可用。

  對于這個問題,更好的解決方案是通過應用程序之外的一組規則來實現某些業務決策。這些規則并沒有被編譯到應用程序中,而是在運行時讀取并應用。通過這種方式,無需更改代碼或者停止正在運行的應用程序就可以改變這些規則。

  WebLogic Portal包括一個基本的規則引擎,用于使WebLogic Platform應用程序從規則獲益。盡管該引擎不是功能完備的產品,但我們將展示如何將其與WebLogic Integration Business Processes (JPDs)一起使用來為業務邏輯提供一種靈活且動態的實現機制,從而無需只為了修改規則而重新部署應用程序。

  首先我們來看一下將在全文中使用的示例應用程序,然后介紹如何將規則引擎注入到WLI流程中以實現業務邏輯。然后,我們將更仔細地研究這些規則本身以及如何為業務邏輯定義這些規則,最后將描述在運行中的系統中更改業務規則所使用的機制。

  示例應用程序

  我們將開發一個示例交易應用程序作為在業務流程中使用規則的例子。該交易應用程序是一個金融交易流程的簡化版本,該流程使用調用規則引擎的JPD業務流程而構建。該示例應用程序采用了不同的有價證券交易集合,并根據一組由業務定義的規則將其分組成交易塊以便執行,或許是為了減少傭金。當然,這里給出的應用程序并不完整,但它已經足以展示如何在現實世界應用程序中使用規則引擎。有完整的源代碼可供下載,其中的readme文件提供了構建和運行該應用程序的說明。

  在解釋如何開發這樣的應用程序之前,我們先通過對門戶規則引擎的一些特性的簡要概括來了解其工作方式。這里假定讀者熟悉一般的規則技術。

  規則引擎及其工作方式

  圖1說明了規則引擎的基本情況。該引擎根據一組規則來處理初始的事實集,而這些規則由引擎從外部庫中獲得。初始事實用于為該引擎填充工作內存。由規則來對工作內存中的事實進行評估,如果滿足某條規則的條件,則將執行對應的動作。通常,一個規則動作將向工作內存中添加一條新的事實,并重復該流程直到應用完所有的規則。然后通過可選的過濾器來選擇特定類的對象以返回給調用方??梢酝ㄟ^Controls界面訪問規則引擎,還可以用它來設置屬性(比如規則集文件的位置)。

使用WEBLOGIC PORTAL規則引擎中實現動態業務邏輯

  圖1:該規則引擎是一個由控件包裝的EJB。儲存庫中的規則反復地應用于工作內存中的事實,以獲得新的事實。在無法進行繼續推理的情況下,對工作內存進行過濾以返回感興趣的項目。

  從WLI流程調用規則引擎

  讓我們從被實現為JPD的交易業務流程開始,來看看如何添加對規則引擎的調用。要在WLI流程中添加規則,可以使用作為WebLogic Portal的一部分而提供的Rules Executor Control(規則執行器控件)。對于本例,我們只使用該控件中所提供的方法和特性的一個子集。關于規則控件的附加說明文檔可以在參考資料部分找到。

  此處假定開發人員使用WebLogic Workshop集成開發環境來創建新的流程應用程序。然后可在該應用程序中創建一個流程項目。因為默認情況下門戶控件在流程項目中不可用,所以需要將這些控件和規則引擎的EJB導入到應用程序。然后,將控件輸入和輸出插入到JPD中。在WLI流程中使用門戶規則引擎的基本步驟如下:

  導入規則引擎到應用程序:

  • 在應用程序中包含規則引擎。
  • 將p13n_controls庫添加到應用程序。

  處理輸入和輸出:

  • 為輸入和結果添加變量。
  • 創建一個Rules Executor控件。
  • 在WLI流程中添加一個Control Send With Return節點。
  • 為創建初始數據編寫Java代碼。
  • 添加一個流程節點以對結果進行迭代。
  • 創建規則集。

  后面我們將更詳細地討論其中的每一個步驟。

  在應用程序中包含規則引擎

  規則引擎包含在下面的文件中:

  /weblogic81/p13n/lib/p13n_ejb.jar

  要在應用程序中包含該引擎,請右擊Workshop集成開發環境中的Modules文件夾,并選擇Add Module。導航到該jar文件,并選擇Open。

  將p13n_controls庫添加到應用程序

  要使得門戶規則控件在應用程序中可用,請右擊Workshop集成開發環境中的Libraries文件夾,并選擇Add Library。該控件位于:

  </weblogic81/p13n/lib/p13n_controls.jar

  導航到此文件,單擊 Open 按鈕。

  為輸入和結果添加變量

  這里使用的Rules Executor控件方法需要一個對象數組作為輸入并返回一個結果的迭代器。在Workshop集成開發環境中為這些值創建變量,這樣我們就可以在下一步中通過圖形用戶界面來創建控件。要完成該任務,請為Data Palette中的變量單擊Add按鈕,鍵入輸入變量的名稱,并鍵入Java類型java.lang.Object[]。使用同樣的方式創建Java類型為java.util.Iterator的輸出變量。

  創建一個Rules Executor控件

  要創建規則控件,請單擊Data Palette中控件的Add按鈕。從菜單中選擇Portal Controls -> Rules Executor。為控件鍵入名稱,并按下Create按鈕。

  在WLI流程中添加一個Control Send With Return節點

  將剛剛創建的控件拖放到流程中以創建一個控件節點來實際調用規則引擎。在示例中,我們將使用控件的evaluateRuleSet()方法。從Send Data面板中,選擇前面為方法的輸入參數而創建的輸入變量。使用Receive Data面板選擇返回變量來獲取規則執行的結果。在Property Editor窗口中為控件屬性鍵入相應的值。

  為創建初始數據編寫Java代碼

  在創建了輸入變量后,我們還沒有對它賦值,所以需要編寫代碼來完成該任務。這個變量是一個Java對象數組,它提供了輸入到規則條件中的初始事實??梢詣摻ㄒ粋€新的Perform節點來初始化該數組,或者通過使用Source View在Control Send節點中添加代碼來設置該變量的值。

  添加一個流程節點以對結果進行迭代

  Rules Executor控件的每一個計算方法都將返回一個結果的迭代器。編寫代碼,使用該值實現對規則執行結果的迭代。如果沒有指定過濾器類,這個迭代器將返回規則引擎工作內存中的所有值。其中包括原始輸入以及任何在執行滿足條件的規則的動作時添加到工作內存中的值。對于添加的對象,迭代器返回一個Result類的對象,該類的getObject()方法可以返回在規則動作中所添加的實際對象。

  創建規則集

  使用XML編輯器,在/META-INF/data目錄中創建一個擴展名為.rls的文件。規則通常添加到子目錄rulesets中。

  業務邏輯規則

  我們剛剛展示了如何在業務流程中插入規則引擎?,F在讓我們來看看如何利用該規則引擎以及如何編寫映射到業務規則的規則。

  規則包括兩個部分:應用該規則時必須為真的條件,以及當條件滿足時將執行的動作。因此,要在應用程序中使用規則,設計人員必須首先定義哪些對象和屬性在測試規則條件時對規則編寫者是可見的。規則引擎允許在一個條件中調用任意多個方法。這種構造方式便于定義JavaBean作為組成初始事實集合的對象,規則引擎使用這些初始事實來進行推理??梢允褂胋ean的 get方法來獲得條件測試的值。

  規則所引用的Java對象需要從創建它的WLI流程以及從規則引擎本身中都可見。這就避免了這些對象與流程JPD位于同一包中,更確切地說,它們應該被創建于作為同一應用程序的一部分的Java項目中。然后,這些對象可以通過package.class標記在規則文件(.rls)和流程JPD中引用。

  在我們的交易示例中,將把不同的交易分組以便可以成塊執行。為實現該目標,我們定義兩個bean來表示相關的對象。第一個是Trade bean,它表示單個的交易訂單。這個bean的屬性表示交易的份額、股份數目以及所期望的價格等。任何對于決定交易所屬的塊來說可能有用的值,都應該作為這個具有公有get方法的bean的屬性,以便能夠在規則中使用它。第二個bean是Block bean,通過它可以存儲所有根據某個屬性集聚合在一起的不同交易。這個bean的屬性包括規則中任何可用于判定塊大得足以執行訂單的的信息。這些屬性可以是平均價格、交易的總美元數或總的份額數等等。

  為了在我們的應用程序中實現塊功能,首先使用規則來定義某項交易是否只需要執行其自身就足夠了(也就是說,它是僅包含單個交易的塊),或者如果不是這樣的話,那么應該使用什么屬性將其與其他交易聚集以形成一個塊。在一項交易聚集到適當的塊中后,就會第二次調用規則引擎來判斷該塊是否完成。例如,假設我們想要得到這樣的規則:

  • 規則1:任何5,000股及以上的單項交易應該作為一個塊并予以執行。
  • 規則2:由同一個投資管理者定購的具有相同標記的交易應該聚集在一起。
  • 規則3:總價值超過,000的塊應該予以執行。

  調用與規則條件中的對象相關聯的方法很容易,如下面的示例所示,這是規則1的條件:

<cr:conditions>
  <greater-than-or-equal-to>
    <instance-method>
      <variable>
        <type-alias>Beans.Trade</type-alias>
      </variable>
      <name>getQuantity</name>
      <!-- getQuantity (and any other bean property) takes
           no arguments.  If it did, they
           would go here
        <arguments>...</arguments>
      -->
    </instance-method>
    <literal:integer>
      5000
    </literal:integer>
  </greater-than-or-equal-to>
</cr:conditions>

  在這個示例中,如果在我們的事實中有一個Trade對象,那么規則引擎就會調用它的getQuantity()方法并且將結果與整型5000進行比較。如果它大于或等于5000,則該條件為真。

  規則的第二部分是條件滿足時執行的動作的列表。最常見的動作是:創建一個新對象,把它添加到規則引擎用來評估條件的事實集中。規則引擎繼續對規則進行迭代,直到無法從事實中得出更多的推理;向動作添加新對象會導致另一輪的條件評估循環。正如我們將要看到的那樣,可以創建任意類型的對象,并定義對應用程序具有特定意義的各種類型。這里的技巧是,應用程序設計者可以定義一組足夠豐富的動作,以包含那些可由規則編寫者調用以滿足各種業務需求的任務。

  在我們的交易應用程序示例中,所有動作都會創建將添加到由規則引擎使用的工作集中的新對象。有些規則向該集合中添加簡單的String對象。這些對象表示了從原始事實中演繹出來的中間事實,它們可以在規則引擎中得到進一步的推理,但流程JPD不會以任何形式解釋它們。其他的規則將創建Beans.Action類的對象。這些對象包括當規則條件滿足時流程將執行的實際命令。流程JPD和支持類將實施已知的動作命令來聚集交易并執行塊交易。在這個簡單的示例中,實際上只有兩個已知的命令:創建(并執行)訂單、使用指定的屬性聚集一項交易。前面規則2的動作是使用屬性symbol和manager來進行聚集,該動作如下:

<cr:actions>
  <new-instance>
    <type-alias>Beans.Action</type-alias>
    <arguments>
      <literal:string>symbol, manager</literal:string>
    </arguments>
  </new-instance>
</cr:actions>

  響應該動作,流程JPD及其支持類為當前交易查詢symbol和投資manager,找出具有相同的symbol和投資manager的未執行交易,并將這些交易聚集到相同的塊。

  在完成一項交易的聚集后,將從第二個Rules Executor控件再次調用規則引擎,以評估規則,決定是否應該執行產生的塊交易。根據業務規則3,該規則如下:

<cr:conditions>
  <greater-than >
    <instance-method>
      <variable>
        <type-alias>Beans.Block</type-alias>
      </variable>
      <name>getAmount</name>
    </instance-method>
    <literal:float>
      50000.00
    </literal:float>
  </greater-than >
</cr:conditions>
<cr:actions>
  <new-instance>
    <type-alias>Beans.Action</type-alias>
    <arguments>
      <literal:string>create</literal:string>
    </arguments>
  </new-instance>
</cr:actions>

  這一次,我們分析Beans.Block對象,獲取amount屬性并與閾值進行比較。如果該條件滿足,則使用create命令向工作集中添加一個Beans.Action對象,這是通知流程執行該塊訂單的信號。

  讓我們仔細分析一下流程JPD。下面有用于調用規則引擎的Control Send節點的代碼。正如我們可以看到的,該節點使用一個Rules Executor控件來評估規則集,該控件返回一個迭代器。通過其屬性(沒有給出),控件將過濾結果,僅返回Beans.Action類的對象。通過這些對象,代碼將提取動作命令并執行所請求的動作。正如前面所提到的,如果動作是聚集該交易,則流程將使用更新后的塊作為輸入,對規則引擎開始第二次調用。通過執行適當的動作,對結果進行第二次迭代循環。

public void rulesExecutorControlEvaluateRuleSet()
    throws Exception
{
    // Execute the Rules using facts as the input 
    //#START: CODE GENERATED - PROTECTED SECTION - you can safely
      // Add code above this comment in this method. #//
    // Input transform
    // Return method call
    this.results =
        rulesExecutorControl.evaluateRuleSet(this.facts);
    // Output transform
    // Output assignments
    //#END  : CODE GENERATED - PROTECTED SECTION - you can safely 
      // Add code below this comment in this method. #//

    /* Iterate over the results of rules execution. This assumes that
       results are filtered to return only items of the Beans.Action class.  
       The command property from the Action is expected to be either the
       string "create," in which case a Block trade can be executed from
       the single discrete Trade, or it is expected to be a list of
       attributes describing the Block that this Trade should be 
       incorporated into.
     */
    while (results.hasNext())
    {
        String action = 
            ((Action)results.next()).getCommand();
        if (action.equals("create"))
            (new Block(trade)).execute();  // single-trade       
        else
        {
            // Aggregate trade into an intermediate Block
            trade.aggregate(blockStorage, action);
                
          /* Call the rules engine a second time, this time using
             the resulting Block as the only input.  This is to
             determine if the resulting Block now meets the criteria 
             to execute the order. Again, results are assumed to be
             filtered by the control to return only the Actions.
            */
            Block block = trade.getBlock();
            Object blockFacts[] = new Object[1];
            blockFacts[0] = block;
            Iterator blockResults = 
                blockRulesCntl.evaluateRuleSet(blockFacts);
            while (blockResults.hasNext())
            {
              action = 
                ((Action)blockResults.next()).getCommand();
              if (action.equals("create"))
                  block.execute();
            }
        }
    }
}

  動態規則

  WebLogic Portal的特性之一是Datasync功能,通過它可以將修改后的數據重新部署到集群中的門戶應用程序中。因為門戶規則引擎從Datasync存儲區中獲得其規則文件,所以應用程序的業務規則可以在運行的系統中進行更改,而無需停止應用程序。關于Datasync以及用于更新數據的Datasync Web應用程序的其他信息,請參閱WebLogic Portal文檔。

  默認情況下,Datasync Web應用程序將部署在常規門戶應用程序中。然而,我們的示例應用程序是一個WLI流程應用程序,因此必須在其中手動地包含Datasync。要在Workshop集成開發環境中完成這些工作,請右擊Modules文件夾,并選擇Add Module。然后,選擇下面的文件:

  /weblogic81/p13n/lib/datasync.war

  在集群中,Datasync應用程序應該僅部署到管理服務器。

  為了闡明如何在運行中的應用程序中更改規則,示例應用程序中包括了兩個不同的規則文件,這兩個文件中包括了用于將交易聚集成塊的可選規則。前面已經描述了默認規則(定義于traderules.rls文件中),第二個集合(在altrules.rls中)定義如下規則:

  • 按照標記將所有的交易聚集成塊。
  • 執行包含3,000或更多股的塊。

  要看到動態規則的執行,首先使用所提供的測試數據運行示例應用程序。無需停止服務器或者重新部署應用程序,直接將原始規則保存到一個新文件中,并將替代的規則文件從:

  /META-INF/data/rulesets/altrules.rls

  拷貝到:

  /META-INF/data/rulesets/traderules.rls

  再次運行示例數據,這時會發現產生了不同的訂單。

  注意,在示例域中不需要重新運行Datasync Web應用程序來更新規則。這是因為示例平臺域以開發模式運行。在這種模式下,Datasync自動輪詢 /META-INF/data目錄及其子目錄以搜索更改,更改過的文件可以自動地重新部署到應用程序。在生產域中,需要使用Web應用程序來實現數據的重新部署。推薦的步驟是,首先為所有更新過的文件創建一個jar文件,jar文件的根目錄應該是data。然后,使用Datasync Web應用程序的Bootstrap Data功能來重新部署包含了新規則的jar文件。

  下載

  您可以下載本文中使用的示例程序的源代碼:SampleApp.zip (2MB)

  結束語

  在與WLI流程應用程序一起使用時,Portal Rules Engine是實現業務邏輯的強大工具。它很容易合并到WLI流程中,并且可以使用JavaBean來評估規則條件,或者擴展作為規則評估結果而執行的動作。最后,Datasync特性所提供的動態更新能力使得業務邏輯更靈活,并能夠在不改變Java代碼的前提下適應不斷變化的需求,所以不需要重新部署應用程序。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97