ApplicationData(アプリケーションデータ)

印刷

ApplicationData(アプリケーションデータ)について

 droolsの機能として、Application Dataという機能があります。通常、droolsを用いてルールを用いたプログラムを作ろうとする場合、ルール部分(ルールベース、ワーキングメモリ、ルールエンジン)とJava本体プログラムとのやりとりは、本体でのインスタンスを fact としてワーキングメモリに assert し、そこを通じて行うことになります。

通常のdroolsの動き

しかし、実際のプログラミングを行っていると、ルールの記述の中で、例えば、「数値の比較部分で、ちょっとJava本体のプログラムで行った計算結果を使いたい。」などという場合や、「GUIの画面に直接結果を表示したい」などという場合が出てきます。こういったときに、いちいち fact を assert して云々というのもかなり煩わしいものでしょう。Application Dataは、このようにルールの条件部のパラメータとして、本体プログラムの結果をちょっと参照したいとか、GUIの画面に結果を直接表示したいというようなときに威力を発揮します。

アプリケーションデータを用いたdroolsの動き

使い方としては、 

ルールの記述ファイル(.drl)に

  <application-data identifier="amount">java.lang.Integer</application-data>
       (amountがルールファイルの中で参照する識別子、java.lang.Integerが、amountのデータ型)

と宣言することで、まずルールの条件部(condition部)、結果部(consequence部)でamountという識別子を使うことができるようになります。(例は、droolsページのApplication Data の項からとっています)

この上さらに本体のプログラムのほうで、

 workingMemory.setApplicationData("amount",new Integer(3));

と記述することによって、ルールの記述ファイルの中での識別子amountに対して、実体が与えられるということになります(ちなみに基本データ型については、上記のようにラッパを使う必要があります)。

 それでは、実際のプログラムとして、JavaのSWTで入出力画面を作って、出張日当の計算のプログラムにかぶせてみましょう。ここでは、Application Dataの例として、ごく簡単に作ってみました(入力チェックなども行っていません)。

BusinessTrip.javaは、droolsのサンプルプログラムで作成したプログラムと同じ(パッケージ名は変えています)ですが、mainプログラムとsample.drlが若干記述が変わってきます。(mainプログラムについては、EclipseのVisualEditorを使って書くのが最も簡単と思います。)

BtripSample.java(メインプログラム:太字の部分は、VisualEditorで自動生成したプログラムに後から加えたもしくは修正した部分

package drools.example.applidata;

import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.io.RuleBaseLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.graphics.Rectangle;

public class BtripSample {

    private Shell sShell = null;
    private Label label = null;
    private Text text = null;
    private Button button = null;
    private Label label1 = null;
    private Text text1 = null;
    private Text textArea = null;
    private static RuleBase ruleBase = null;
    private static WorkingMemory workingMemory = null;


    public static void main(String[] args) {
        Display display = Display.getDefault();
        BtripSample thisClass = new BtripSample();
        thisClass.createSShell();
        thisClass.sShell.open();

        try {
        ruleBase = RuleBaseLoader.loadFromUrl(
                  BtripSample.class.getResource("sample.drl") );
                
        workingMemory = ruleBase.newWorkingMemory();
        
        workingMemory.setApplicationData("frame", thisClass);
        } catch (Exception e) {
            e.printStackTrace( );
        }

        while (!thisClass.sShell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }

    private void createSShell() {
        sShell = new Shell();
        sShell.setText("出張日当計算");
        sShell.setLayout(null);
        sShell.setSize(new Point(300, 200));
        label = new Label(sShell, SWT.NONE);
        label.setFont(new Font(Display.getDefault(), "MS UI Gothic", 9, SWT.BOLD));
        label.setBounds(new Rectangle(5, 10, 26, 12));
        label.setText("名前");
        text = new Text(sShell, SWT.BORDER);
        text.setBounds(new Rectangle(98, 7, 71, 18));
        button = new Button(sShell, SWT.NONE);
        button.setFont(new Font(Display.getDefault(), "MS UI Gothic", 10, SWT.BOLD));
        button.setBounds(new Rectangle(174, 5, 40, 23));
        button.setText("計算");
        button.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
                try {
                workingMemory.assertObject(new BusinessTrip(text.getText(),
                                                     Double.valueOf(text1.getText()).doubleValue()));
                workingMemory.fireAllRules();
                } catch (Exception fe) {
                    fe.printStackTrace( );
                }
            }
        });
        label1 = new Label(sShell, SWT.NONE);
        label1.setFont(new Font(Display.getDefault(), "MS UI Gothic", 9, SWT.BOLD));
        label1.setBounds(new Rectangle(5, 36, 52, 12));
        label1.setText("出張時間");
        text1 = new Text(sShell, SWT.BORDER);
        text1.setBounds(new Rectangle(98, 33, 71, 18));
        Label filler = new Label(sShell, SWT.NONE);
        filler.setBounds(new Rectangle(174, 36, 0, 12));
        textArea = new Text(sShell, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER | SWT.READ_ONLY);
        textArea.setBounds(new Rectangle(6, 56, 275, 101));
    }

    public void textDisplay(String str) {
        textArea.append(str + "\n\r");
    }    
    
}

 

 

 sample.drl

 <?xml version="1.0" encoding="UTF-8"?>
<rule-set name="daily allowance"
          xmlns="http://drools.org/rules"
          xmlns:java="http://drools.org/semantics/java"
          xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
          xs:schemaLocation="http://drools.org/rules rules.xsd
                             http://drools.org/semantics/java java.xsd">
 
  <java:import>drools.example.applidata.BusinessTrip</java:import>
  <java:import>drools.example.applidata.BtripSample</java:import>
  <application-data identifier="frame">BtripSample</application-data>
 
  <rule name="日当なし">
    <parameter identifier="btrip">
      <class>BusinessTrip</class>
    </parameter>
    <java:condition>btrip.getHour() &lt; 4.0</java:condition>
    <java:consequence>
      System.out.println(btrip.getName()+"さんの出張時間は、"
      +btrip.getHour()+"時間なので、日当はありません。 (ルール:日当なし)");
      frame.textDisplay(btrip.getName()+"さんの出張時間は、"
      +String.valueOf(btrip.getHour())+"時間なので、日当はありません。 (ルール:日当なし)");
    </java:consequence>
  </rule>
 
  <rule name="日当C">
    <parameter identifier="btrip">
      <class>BusinessTrip</class>
    </parameter>
    <java:condition>4.0 &lt;= btrip.getHour()</java:condition>
    <java:condition>btrip.getHour() &lt; 8.0</java:condition>
    <java:consequence>
      System.out.println(btrip.getName()+"さんの出張時間は、"+btrip.getHour()+"時間なので、日当は1000円です。 (ルール:日当C)");
      frame.textDisplay(btrip.getName()+"さんの出張時間は、"
      +String.valueOf(btrip.getHour())+"時間なので、日当は1000円です。 (ルール:日当C)");
    </java:consequence>
  </rule>

  <rule name="日当B">
    <parameter identifier="btrip">
      <class>BusinessTrip</class>
    </parameter>
    <java:condition>8.0 &lt;= btrip.getHour()</java:condition>
    <java:condition>btrip.getHour() &lt; 12.0</java:condition>
    <java:consequence>
      System.out.println(btrip.getName()+"さんの出張時間は、"+btrip.getHour()+"時間なので、日当は2000円です。 (ルール:日当B)");
      frame.textDisplay(btrip.getName()+"さんの出張時間は、"
      +String.valueOf(btrip.getHour())+"時間なので、日当は2000円です。 (ルール:日当B)");
    </java:consequence>
  </rule>

  <rule name="日当A">
    <parameter identifier="btrip">
      <class>BusinessTrip</class>
    </parameter>
    <java:condition>12.0 &lt;= btrip.getHour()</java:condition>
    <java:consequence>
      System.out.println(btrip.getName()+"さんの出張時間は、"+btrip.getHour()+"時間なので、日当は3000円です。 (ルール:日当A)");
      frame.textDisplay(btrip.getName()+"さんの出張時間は、"
      +String.valueOf(btrip.getHour())+"時間なので、日当は3000円です。 (ルール:日当A)");
    </java:consequence>
  </rule>

</rule-set>

 

 これを動かすと、下記のようになります。

画面