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

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


# Droolsとは？
BRMS(Business Rule Management System)製品の一つ。JBoss Rulesのコミュニティ版として提供されているもの。  
他のBRMS製品だと、IBM Operational Decision Managerとか。

Apacheソフトウェアライセンス2.0の下でリリースされたオープンソースのソフトウェア([Droolsのライセンス情報へのリンク](http://www.drools.org/code/license.html))。
なので、商用利用の敷居が低い。

従来からビジネスルール(業務ロジックと言った方がしっくりするか)は、
そのアプリケーション内部にハードコーディングしていました(今もほとんどがそうしている)。
当然、そのアプリケーションが採用しているプログラミング言語でコーディングしているので、
ビジネスルールを提供する側(いわゆる業務側)からすると、そのコードを見せられても解りません。

# BRMSっておいしいの？
__ビジネスルールの見える化__をしたいならお勧めかと。  
例えば、プログラミング言語で記述されたビジネスルール(そのプログラミング言語のIF文で記述されたルール)よりは、
Excelで記述されたディシジョンテーブル形式のビジネスルールの方が解りやすいと思います。
Droolsでは、Excelでディシジョン形式のルールを記述し、それをルールエンジンで利用することができます(Droolsでは他にもグラフィカルに表現するツールを持っている)。

他にもうたい文句で、業務側自らで、ビジネスルールを変更できるので、仕様変更に柔軟に対応できるとか、ビジネスルールをホットデプロイできますよとかあります。
が、ろくにテストもしていないビジネスルールを、ホイホイとデプロイされたらたまったもんではないので、__見える化__がいいとこ。
(ビジネスルールのテスト環境を充実させれば、ありですが・・・)

__他にもこんな機能を提供__  

* BRE(Business Rule Engine)、ビジネスルールエンジン。コア機能。  
* Webオーサリングツール。  
* ルール管理アプリケーション(Droolsのワークベンチ)。  
* コア開発用のEclipse IDEのプラグイン。  

---

# 本題

下記コード断片の全体は、次のGitHubを参照。[PRJ_Drools](https://github.com/madilloar/PRJ_Drools)

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

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ドキュメント](http://docs.jboss.org/drools/release/6.3.0.Final/drools-docs/html_single/index.html)  
の「4.2.2.4. Defining a KieModule programmatically」を参考にしました。

[Stack Overflow](http://stackoverflow.com/questions/24558451/cant-run-hello-world-on-drools-dlr-files-are-not-picked-from-classpath-by-kie)  
の「Can't run hello world on drools - dlr files are not picked from classpath by KieContainer」を参考にしました。

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

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

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

```java
    // ルールファイルを読み込む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));
    
```

---

## その２: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](https://docs.jboss.org/drools/release/5.2.0.M2/drools-expert-docs/html/ch05.html)