Usual Software Engineer

よくあるソフトウェアエンジニアのブログ

DroolsでPPAP

Droolsって知っていますか?おそらく知っている方はかなり少ないのではないかと勝手に思っています。 Droolsとは、JBossが開発しているOSSビジネスロジック統合プラットフォームです。簡単にはルールエンジンとして使えます。 ルールエンジンとは、ある特定のビジネスロジックをIF文のコードではなく表やツリーなどで表現し、入力に対してそれを適用することで期待する動作を行うためのプログラムのことです。 if-thenの条件定義がdrlファイルで設定でき、そのdrlファイルは表形式などのGUIで生成できるので、ビジネスロジックに関する意思決定者がエンジニアでなくても直接変更することができるところが魅力なのかなと思います。

今回はこのDroolsの紹介のためにPPAPブームにあやかることにしました。 正直PPAPとかよくわからないですがノリで良いんじゃないかと思います。深く考えたら負けです。 Droolsアーキテクチャの説明から入るとかなりボリューミーで苦しい感じになるので ここではDroolsでできることの基礎だけ載せます。あとDroolsではWorkbenchというアプリケーションが非常に重要なのですが、それも今回は触れないことにします。
なおPPAPの紹介はありませんが、このエントリによってDroolsでPPAPが理解できたら嬉しいです。たぶんできません。

DroolsでPPAP

まずmodelを用意します。

src/main/java/innossh/drools/ppap/model/Apple.java src/main/java/innossh/drools/ppap/model/Pen.java src/main/java/innossh/drools/ppap/model/Pineapple.java

public class Apple {
}

public class Pen {
}

public class Pineapple {
}

なんという手抜き。続いてruleを用意します。
メインのdrlファイルとkmodule.xmlという設定ファイルが必要になります。kmodule.xmlはルールを実行するためのsessionの定義などを行います。

src/main/resources/META-INF/kmodule.xml

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
    <kbase name="PpapKBase" packages="PpapKBase">
        <ksession name="PpapKBase.session" type="stateful" />
    </kbase>
</kmodule>

src/main/resources/META-INF/PpapKBase/rules.drl

package innossh.drools.ppap;

import innossh.drools.ppap.model.Apple;
import innossh.drools.ppap.model.Pen;
import innossh.drools.ppap.model.Pineapple;

declare ApplePen
end

declare PineapplePen
end

rule "When you have a pen and an apple"
when
    $pen : Pen()
    $apple : Apple()
then
    System.out.println("I have a pen");
    System.out.println("I have an apple");
    insert(new ApplePen());
    System.out.println("Apple-pen!");
end

rule "When you have a pen and a pineapple"
when
    $pen : Pen()
    $pineapple : Pineapple()
then
    System.out.println("I have a pen");
    System.out.println("I have a pineapple");
    insert(new PineapplePen());
    System.out.println("Pineapple-pen!");
end

rule "When you have an applepen and a pineapplepen"
when
    $applePen : ApplePen()
    $pineapplePen : PineapplePen()
then
    System.out.println("Apple-pen...");
    System.out.println("Pineapple-pen...");
    System.out.println("Pen-Pineapple-Apple-Pen!");
end

drlファイルには複数のルールを定義することが可能で、互いのルールが依存関係にある場合にはよしなに解釈してくれます。 またApplePenクラスやPineapplePenクラスはmodelとして作りませんでしたが、drlファイル内で declare ~ として定義することができます。
あとはこのルールを実行するメインクラスもしくはテストクラスを作りましょう。

src/test/java/innossh/drools/ppap/PpapTest.java

package innossh.drools.ppap;

import innossh.drools.ppap.model.Apple;
import innossh.drools.ppap.model.Pen;
import innossh.drools.ppap.model.Pineapple;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

import static org.junit.Assert.assertEquals;


public class PpapTest {

    @Test
    public void testPpap() {
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("PpapKBase.session");

        Pen pen = new Pen();
        Apple apple = new Apple();
        Pineapple pineapple = new Pineapple();
        kieSession.insert(pen);
        kieSession.insert(apple);
        kieSession.insert(pineapple);

        int rules = kieSession.fireAllRules();
        assertEquals(3, rules);
    }

}

まず疑問に思うのが KIE ってなんぞ? kmodule も k が付いていたし。というところですよね。 これはKnowledge is Everythingの略らしく、Droolsよりも広いJBossオープンソースプロジェクトの名前らしいです。KIEプロジェクトの中にDroolsやその他のオープンソースプロダクトが含まれているイメージでしょうか。そのため各種ライブラリにkieという名前が付いているようです。
実行の流れはsessionを作成しそこにpen, apple, pineappleを追加してあげてruleをfireするといった具合です。 実行結果は...

I have a pen
I have an apple
Apple-pen!
I have a pen
I have a pineapple
Pineapple-pen!
Apple-pen...
Pineapple-pen...
Pen-Pineapple-Apple-Pen!

はい。おもしろいでしょうか!その答えはPPAPにあるでしょう。
...
とってもシンプルなコードをわざわざちゃんと読んだ人は気づいたかもしれませんが、ペンパイナッポーアッポーペンにはペンが2つ必要になるはずなのに、 sessionへの入力には1つのペンしか使用していませんね。 入力された要素はDroolsではFactと呼ぶのですが、このFactは全てのルールに与えられます。そのためペンが1つでもルールの条件が成立し意図した結果が得られます。
ちなみにDroolsのルールの実行回数はなかなか制御が難しいところで、簡単に無限ループを発生させるルールを書いてしまいます。気を使う必要があるのでDroolsを使ったからといって簡単にエンジニアの手から離れることはなさそうだなと思いました。

余談

Droolsの情報はかなり少ないです。公式ドキュメントはキャプチャが古いしリンク切れも多いし、ググればGoogle Groupsのやり取りばかりがヒットし、StackOverFlowやJIRAでは質問は見つかれどだれもコメントをしていないなど、精神的につらいです。なのでDroolsのエントリがどなたかの手助けになれば幸いです。Droolsについてもっと書かなくては。
情報少ないのにコミュニティとしてはアクティブにも見えるし次期バージョンのbetaも公開されているので、ユーザがいるのかいないのか謎に包まれているのですが、 個人的な見解ではエンタープライズ版は使われていて、その運用はJBossのエンジニアがやっているから特に外部に情報も少なく、OSS版であるDroolsオープンソースになっていることに意義があるだけで実際のユーザは少ないのではないか、と予想しています。間違っていたらJBossの方々ごめんなさいね。