Drools 5.0 入門 3A (IDEとプロジェクトの作成・実行)

Rule Resource1

 せっかくEclipseIDEをインストールしたので、IDEを使っていくつかサンプルプログラムを動かしてみましょう。Droolsの概念的な動きについてはすでにDrools 4.0 入門4 (Droolsの動き)で書いているのでそちらを参照するとして、ここでは具体的なプログラムを見ていきましょう。

サンプルプログラムの仕様0

 まずはごく簡単に・・・スーパーでのキャンペーン割引ということで

 ・5000円以上お買い上げの場合一律に500円を割引する

というルールがあったとしましょう。以下でこのルールを具体化します。それと同時にルールを動かすための準備やデバッグの情報の表示についてなどについても見てみましょう。

プログラム

 ルールを適用していくためには、そのための準備が必要です。Droolsの動き(Drools 4.0 入門4 (Droolsの動き))でも説明したワーキングメモリ(WorkingMemory)やルールベース(RuleBase)の設定、それからワーキングメモリの要素となるファクト(fact)の構造の宣言などが必要となります。

 ではプログラムにそって見ていきましょう。 まずはルールを実行する前の準備としてルールベース、ワーキングメモリの環境を設定します。Droolsでは、まずKnowledgeBuilderを作り、そこへルールファイルをコンパイルして追加します(ここでは追加するルールファイルは一つですが、複数のルールファイルを追加することもできます)。ルールを追加し終えたKnowledgeBuilderからパッケージを取得し、さらにパッケージをKnowledgeBaseにデプロイすることで、いわゆるルールベースが有効になります。さらにこのKnowledgeBase(ルールベース)からStatefulセッションを作成することでワーキングメモリも有効となります。

 これで最低限の準備はできたわけですが、今回はさらにIDEでルールの実行の様子(Agendaの内容、WorkingMemoryの内容)を見るためにそれぞれのEventListenerを追加し、さらにAuditログの設定も追加しておきましょう。

DroolsTest1.java

package jp.co.iluminado.example;

import java.util.Collection;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.definition.KnowledgePackage;
import org.drools.event.rule.DebugAgendaEventListener;
import org.drools.event.rule.DebugWorkingMemoryEventListener;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;

/**
 * This is a sample file to launch a rule package from a rule source file.
 */
public class DroolsTest1 {

    public static final void main(final String[] args) throws Exception {
        final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory
                .newKnowledgeBuilder();

        // ルールファイルをコンパイルしてKnowledgeBuilderへ追加する
        kbuilder.add(ResourceFactory.newClassPathResource(“DroolsTest1.drl”,
                DroolsTest1.class), ResourceType.DRL);

        // 上記コンパイル時のエラー処理
        if (kbuilder.hasErrors()) {
            System.out.println(kbuilder.getErrors().toString());
            throw new RuntimeException(“Unable to compile \”DroolsTest1.drl\”.”);
        }

        // KnowledgeBuilderからコンパイル済みのパッケージを取得する
        final Collection<KnowledgePackage> pkgs = kbuilder
                .getKnowledgePackages();

        // 取得したパッケージをKnowledgebaseに追加する(パッケージのデプロイ)
        final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages(pkgs);

        // Statefulセッションを作成
        final StatefulKnowledgeSession ksession = kbase
                .newStatefulKnowledgeSession();

        // Agenda,WorkingMemoryのView表示準備
        ksession.addEventListener(new DebugAgendaEventListener());
        ksession.addEventListener(new DebugWorkingMemoryEventListener());

        // Auditログのセット
        KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory
                .newFileLogger(ksession, “log/DroolsTest1”);

        // ルールの実行
        final Sales sale = new Sales();
        sale.setSales(6000);
        sale.setStatus(Sales.NOT_APPLIED);
        
        ksession.insert(sale);
        ksession.fireAllRules();

        // Auditログを閉じる
        logger.close();

        // Statefulセッションなので、実行が終わったところでdisposeして領域を開放する
        ksession.dispose();
    }

    public static class Sales {
        
        public static final int NOT_APPLIED = 0;  // 未適用
        public static final int APPLIED = 1;        // 適用済

        private long sales;   // 売り上げ
        private int status;   // 状態(未適用、適用済)

        public int getStatus() {
            return this.status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public void setSales(long sales) {
            this.sales = sales;
        }

        public long getSales() {
            return sales;
        }

    }

}

さて、ここではルールの実行に行く前に、ファクト(fact)をあらわすクラスSalesを見ておきましょう。売り上げの価格をあらわすsalesというフィールドと、割引を未適用か適用済かをあらわすstatusというフィールドを持つクラスです。 さらに、ファクトで用いるクラスはJavaBeansになるので各フィールドに対して、accessorメソッドが追加されています。

DroolsTest1.drl

package jp.co.iluminado.example;
 
import jp.co.iluminado.example.DroolsTest1.Sales;

rule “Discount”
    when
        $s : Sales( status == Sales.NOT_APPLIED,
                    $salesValue : sales >= 5000 )
    then
        $s.setSales( $salesValue – 500 );
        $s.setStatus( Sales.APPLIED );
        update( $s );
        System.out.println( $s.getSales() );
end

次にルールを見てみましょう。

 ・5000円以上お買い上げの場合一律に500円を割引する

 という仕様に対しwhen節(条件節)は、ワーキングメモリ中にSalesファクトがあって、そのファクトのstatusが未適用(NOT_APPLIED)であり、salesが5000円以上であると解釈できます。また$s,$salesValueは、それぞれマッチしたSalesファクトに紐づく変数、salesフィールドに紐づく変数でthen節で参照されます。then節ではマッチしたSalesファクトに対して、salesを500円割引して、statusを適用済(APPLIED)にセットしてファクトをupdateします。

 最後にルールの実行部分を。

DroolsTest1.java(一部を再録)


        // ルールの実行
        final Sales sale = new Sales();
        sale.setSales(6000);
        sale.setStatus(Sales.NOT_APPLIED);
        
        ksession.insert(sale);
        ksession.fireAllRules();

        // Auditログを閉じる
        logger.close();

        // Statefulセッションなので、実行が終わったところでdisposeして領域を開放する
        ksession.dispose();
    }

salesを6000円に設定し、statusを未適用の状態にしてワーキングメモリへinsertします。ここでfireAllRules()を動かせばルールが実行されます。実行が終わったところでAuditログを閉じ、セッションも閉じて領域を開放します。

ルールプロジェクトの作成

 まずは、Droolsのプロジェクトを作成して、上記のファイルを作っておきましょう。Droolsのプロジェクト(ここでは、DroolsTest1としておきます)を作成して、DroolsTest1.Javaファイルは、javaのソースの場所にパッケージjp.co.iluminado.exampleを作って、そこに作っておきます。DroolsTest1.drlファイルは、ルールのソースの場所で、右クリックして新しいRule Resourceを作成します。

Rule Resource1

Rule Resource2

 パッケージ名とルールファイル(drlファイル)名を入力してFinishを押すと、Drlファイルのスケルトンができます。ここにDroolsTest1.drlの中身を記述しましょう。

drlファイルのスケルトン

 最後にAuditログを出力するフォルダを作っておかないといけません。作っておかないと実行時にエラーになります。DroolsTest1のプロジェクトを右クリックして、直下に log というフォルダを作っておきましょう。

ルールの実行

 ここで、DroolsTest1.javaを動かしてみましょう。

Run実行結果

6000円から500円割引となった結果System.outに”5500″が表示されています。Agenda、WorkingMemoryのイベントリスナーが設定されているので、System.errにその情報が表示されています。 また、DroolsのAuditビューを表示させておく(Windowメニューのビューの表示(Show View)からできます)と、Auditログの内容が表示されます。

 Auditログ

(表示されない場合は、ビューの右上のOpen Logボタンを押して、Auditログファイル(DroolsTest1.log)を選択してください。)

 

WorkingMemory、Agendaの表示実行

 さらにWorkingMemoryやAgendaの中身を表示させるために、Debugのパースペクティブにし(windowメニューで変更できます) fireAllRules()の行の左端をダブルクリックしてブレークポイントをつけておきましょう。 この状態で、Drools ApplicationとしてDebug実行をすると、ワーキングメモリにファクトを追加した実行直前の状態で一度ブレークします。

ブレークポイントの設定

 

 実際にやってみましょう。ブレークしたところでWorkingMemoryビューを表示し、右上のVariablesビューでksession変数を選択するとワーキングメモリの中身が表示されます。

ワーキングメモリビュー

フィールドsalesの値が6000と設定されたSalesというファクトができていることがわかります。

また、Agendaビューを表示し、同様にksession変数を選択するとアジェンダの中身が表示されます。

アジェンダビュー

アジェンダに見えているActivationの中身がルール”Discount”とそれにマッチしたSalesファクトの組み合わせになっていることにご注意ください。ルールを発火させることで実行が始まりますので、引き続き実行させてみましょう。

引き続き実行

 コンソールにさきほどと同じ結果が表示されているのがわかります。