Drools 4.0 入門2 (サンプルプログラム)

IDE1

 drools2.X,JBoss Rules(drools3)で使用した旅費規程のサンプルを再度drools4で実装してみましょう。IDEを用いたルールプロジェクトの作成方法にしたがって作成してみます。

新しいルールプロジェクトの作成

まず、Eclipseのアイコンのメニューの中のDroolsアイコンの横の▼をクリックして

 IDE1

 

New Rule Projectを選択し、プロジェクト名を入力します。 

 

IDE2

 

 Next > を押すと、標準のサンプルプログラムをデフォルトとして加えておくか否かを聞いてくるので、ひとまずHelloWorldのルールファイルサンプルとJava classサンプルを加えておきましょう。

 

IDE3

Finishを押すと、新しいルールプロジェクトが作成されます。

 

旅費規程のサンプルプログラム

次に、今作成したルールプロジェクトに旅費規程のサンプルプログラムを作ってみましょう。 

旅費規程は、以下のとおりでした。 

旅費規程

  • 1日の出張時間が、4時間未満のとき 日当なし。

  • 4時間以上、8時間未満のとき日当Cで1000円。

  • 8時間以上、12時間未満のとき日当Bで2000円。

  • 12時間以上のとき日当Aで3000円。

これをif-thenの形のルールで書くと

  • if 1日の出張時間 < 4.0時間 then 日当なし。

  • if 4.0時間 <= 1日の出張時間 < 8.0時間 then 日当C:1000円。

  • if 8.0時間 <= 1日の出張時間 < 12.0時間 then 日当B:2000円。

  • if 12.0時間 <= 1日の出張時間 then 日当A:3000円。

です。

 これをさらにdrools4の表現形式に落とすと後述のsample.drlとなりますが、まずsample.drlを説明する前に、若干の準備をしましょう(drools4では、ルールのプログラムはXMLフォーマットではなく、drools独自のフォーマットで記述する.drlファイルとなりました)。
 まずルールの操作対象となる「もの」(ワーキングメモリの要素)はJavaのクラスのインスタンスで表現します。今回の旅費規程において、ルールの操作対象となるのは、「出張」という事象ですので、BusinessTripというクラスを作っておきましょう。

ここに、新たにBusinessTripというクラスを加えます。

BusinessTrip.java

package com.sample;

public class BusinessTrip {
    private String name;
    private double hour;
   
    public BusinessTrip(String name,double hour){
      this.name = name;
      this.hour  = hour;
    }
     
    public String getName(){
      return name;
    }
   
    public double getHour(){
      return hour;
    }
}

DroolsTestでは、ルールベースエンジンを動かす環境設定、ワーキングメモリへの「出張」インスタンスの
書き込み、ルールベースエンジンの実行を行います。この部分は、drools2.xやdrools3.xとも若干変わって
いますが、ルールプロジェクトを作成する際に加えておいたHelloWorldサンプルプログラムを流用することで
容易に作成できます。

HelloWorldサンプルプログラムの内容から変わるところは、旅費規程プログラム用のワーキングメモリを操作する
部分と、メッセージ(message)のクラスを当ファイルから削除したところです。

DroolsTest.java

package com.sample;

import java.io.InputStreamReader;
import java.io.Reader;

import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.WorkingMemory;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;

public class DroolsTest {

    public static final void main(String[] args) {
        try {
           
            //load up the rulebase
            RuleBase ruleBase = readRule();
            WorkingMemory workingMemory = ruleBase.newStatefulSession();
           
            //go !  ↓ここから
            workingMemory.insert(new BusinessTrip(“野中”,3.5));
            workingMemory.fireAllRules();
                  
            workingMemory.insert(new BusinessTrip(“大前”,5.0));
            workingMemory.fireAllRules();

            workingMemory.insert(new BusinessTrip(“米倉”,8.0));
            workingMemory.fireAllRules();

            workingMemory.insert(new BusinessTrip(“嶋口”,10.0));
            workingMemory.fireAllRules();

            workingMemory.insert(new BusinessTrip(“伊丹”,13.0));
            workingMemory.fireAllRules();         

            // ↑ ここまでが旅費規程プログラムのワーキングメモリ操作/実行部分

        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static RuleBase readRule() throws Exception {
        Reader source = new InputStreamReader( DroolsTest.class.getResourceAsStream( “/Sample.drl” ) );
       
        PackageBuilder builder = new PackageBuilder();

        builder.addPackageFromDrl( source );

        Package pkg = builder.getPackage();
       
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        ruleBase.addPackage( pkg );
        return ruleBase;
    }
       
}

 内容は、まずsample.drlのルールを読み込み、ワーキングメモリを作成。次にワーキングメモリの要素を
書き込んでは、ルールを実行(ルールのfire-発火-)、書き込んでは、ルールを実行・・・を繰り返しています。
(ワーキングメモリに一度に全部を書き込んで、最後にまとめてルールの実行をしても結果は同じです)

ビジネスの実際のアプリケーションとなると、これらのインスタンスの情報はデータベースから読み込むとか、
画面からユーザが手で入れるということになりますが、今回はサンプルプログラムということで、簡単のために
メインプログラムにハードコーディングをしてしまいました。

さらに、最後に肝心のルールプログラム。これは、HelloWorldのサンプルルールというよりも
全面的に書き換えてしまいましょう。

 drools4のルールプログラムはdrools2から3に変わるときから変わった以下にみる独自のフォーマット
となっています。
 ”日当なし”のルールを見てみましょう。when部では、ワーキングメモリ中に保持されているBusinessTrip
クラスのインスタンスデータとwhenの部分とがパターンマッチングされ、条件(時間が4時間未満である
BusinessTrip)を満たすデータをとってきて、変数h,nにフィールドの内容を紐付けます(When部では、
アクセサメソッドを利用しなくてもフィールドの値を直接読めます)。
 then部では、when部でインスタンスのデータと紐付けた変数を用いてデータの内容をコンソールに
表示しています。

sample.drl

 package com.sample
 
rule “日当なし”
    when
        BusinessTrip ( h:hour < 4.0 , n:name)
    then
        System.out.println(n+”さんの出張時間は、”
          +h+”時間なので、日当はありません。 (ルール:日当なし)”);
end

rule “日当C”
    when
        BusinessTrip ( h:hour >= 4.0 , hour < 8.0 ,n:name)
    then
        System.out.println(n+”さんの出張時間は、”
         +h+”時間なので、日当は1000円です。 (ルール:日当C)”);
end

rule “日当B”
    when
        BusinessTrip ( h:hour >= 8.0 , hour < 12.0, n:name )
    then
        System.out.println(n+”さんの出張時間は、”
        +h+”時間なので、日当は2000円です。 (ルール:日当B)”);
end

rule “日当A”
    when
        BusinessTrip ( h:hour >= 12.0 ,n:name)
    then
        System.out.println(n+”さんの出張時間は、”
        +h+”時間なので、日当は3000円です。 (ルール:日当A)”);
end

 これを実行すると、

サンプル出力結果

となります。