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

  • 13
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

今回のテーマ

久しぶりに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