Java
Drools
BRMS

DroolsにInputStreamでExcelディシジョンテーブルを食わせる、他

More than 3 years have passed since last update.


今回のテーマ

久しぶりにDroolsを触ったら、3.0系の頃から現在の6.0系で、だいぶ変わっていたので、はまった所の解決策や新たな発見などの紹介です。


Droolsとは?

BRMS(Business Rule Management System)製品の一つ。JBoss Rulesのコミュニティ版として提供されているもの。


他のBRMS製品だと、IBM Operational Decision Managerとか。

Apacheソフトウェアライセンス2.0の下でリリースされたオープンソースのソフトウェア(Droolsのライセンス情報へのリンク)。

なので、商用利用の敷居が低い。

従来からビジネスルール(業務ロジックと言った方がしっくりするか)は、

そのアプリケーション内部にハードコーディングしていました(今もほとんどがそうしている)。

当然、そのアプリケーションが採用しているプログラミング言語でコーディングしているので、

ビジネスルールを提供する側(いわゆる業務側)からすると、そのコードを見せられても解りません。


BRMSっておいしいの?

ビジネスルールの見える化をしたいならお勧めかと。


例えば、プログラミング言語で記述されたビジネスルール(そのプログラミング言語のIF文で記述されたルール)よりは、

Excelで記述されたディシジョンテーブル形式のビジネスルールの方が解りやすいと思います。

Droolsでは、Excelでディシジョン形式のルールを記述し、それをルールエンジンで利用することができます(Droolsでは他にもグラフィカルに表現するツールを持っている)。

他にもうたい文句で、業務側自らで、ビジネスルールを変更できるので、仕様変更に柔軟に対応できるとか、ビジネスルールをホットデプロイできますよとかあります。

が、ろくにテストもしていないビジネスルールを、ホイホイとデプロイされたらたまったもんではないので、見える化がいいとこ。

(ビジネスルールのテスト環境を充実させれば、ありですが・・・)

他にもこんな機能を提供


  • BRE(Business Rule Engine)、ビジネスルールエンジン。コア機能。


  • Webオーサリングツール。


  • ルール管理アプリケーション(Droolsのワークベンチ)。


  • コア開発用のEclipse IDEのプラグイン。




本題

下記コード断片の全体は、次のGitHubを参照。PRJ_Drools


その1:ルールファイルをどうやってルールエンジンに読み込ませるか?

Drools3.Xの頃は、例えば、Excelで作ったディシジョンテーブル形式のルールやDRL(Drools Rule Language)形式は、

自前のjavaアプリケーションからInputStreamで読み込んで、ルールエンジンに与えていました。

それから、ルールエンジンに対するオプションやロガー等もDroolsが提供するAPIを通して設定をしていました。

今の6.0系では、mavenで扱いやすいようになっていて、ルールファイルは"src/main/resources"以下に置く模様。

オプションやロガー等は、"src/main/resources/META-INF/kmodule.xml"ファイルに記述する模様。

Drools6.xのKieScannerクラスを使うと、mavenリポジトリを監視して、新規のルールファイルのリリースが

あればそれをルールエンジンのKieContainerにデプロイしてくれる。

業務システムを構築するならば、こういった仕組みが必要なのも納得。

しかし、


  • ちょいお試し

  • Excelディシジョンテーブル形式の記述がうまく動かないので、途中でDRL形式に変換したをデバッグ出力。

  • ルールファイルをプログラムの中で差し替え。

  • プログラムで、ちょっと加工。
    みたいなことをしたい時は、Drools APIでやりたいものです。

Drools APIを使えば、"kmodule.xml"ファイルが無くてもルールエンジンを動かす事ができます(GitHubのプロジェクトでは使っていません)。

ということで、いくつかコードの断片を。


InputStreamを使ってルールファイルを読む。

Droolsドキュメント


の「4.2.2.4. Defining a KieModule programmatically」を参考にしました。

Stack Overflow


の「Can't run hello world on drools - dlr files are not picked from classpath by KieContainer」を参考にしました。

InputStreamが使えるので、ファイルシステムから読むもよし、プログラムの中で動的にストリームを組み立てて読ませるもよし、色々できるようになります。

ポイントは、"src/main/resources/"の部分。

ルールエンジンのメモリ配置が"src/main/resources/"を前提にしています(mavenを前提にしているためかも)。

はじめ、これが解らず、物理ファイルシステムのパスを相対パスにしてみたり、絶対パスを書いてみたり、パス区切り文字を変えてみたり色々ためしてみましたが、最後、これに行きつきました。

    // ルールファイルを読み込むInputStream

InputStream is = null;
try {
// ルールファイルのストリームを生成。
// DRL(Drools Rule Language)形式でもよいし、excelのディシジョンテーブル形式でもよい。
// drools-decisiontables.jarがクラスパスにないとexcelのディシジョンテーブルは読めません。
is = new FileInputStream(ruleFilePath);
// ルールエンジンのメモリファイルシステム上のデフォルトパスは"src/main/resources/"
kfs.write("src/main/resources/" + ruleFileName, kieServices.getResources().newInputStreamResource(is));



その2:Excelディシジョンテーブルで条件値に定数だけでなく、javaのコードが書ける!!!

今まで知らなったが、試しにやってみたらできた。前からできたのかも。

これまでは、ディシジョンテーブルの条件値をセルに書くときは、定数だけだと思っていましたが、

Javaのコードを書けることが分かりました。

ポイントは、ルールテンプレート部分の「eval($param)」の部分です。

eval関数の中を評価してくれます。eval関数でくくってあげないと、セルの中は単なる文字列として扱われてしまいます。

CONDITION

$pd:ProductDifference

eval($param)

許容範囲

Math.abs(afterProcduct.getHeight() - beforeProduct.getHeight()) < 1

Math.abs(afterProcduct.getHeight() - beforeProduct.getHeight()) >= 1

参考URL:

Chapter 5. The Rule Language