2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Business Automation Manager Open Edition メモ - (5) Embedded形態でのルール開発(DRL編)

Last updated at Posted at 2023-01-04

はじめに

ここまでは、Business CentralやKIE Serverを使ったルールの作成、実行を見てきました。今回はそれらは使わず、できるだけシンプルな構成でルールを取り扱う方法について試してみます。
開発環境としてVS Codeを使用し、ルールサーバーを使わずにいわゆる組み込み型でアプリケーションを動かす流れを試してみます。ルールはDRLおよびExcelで記述することにします。
※当記事で試す手順はスタンドアローンのJavaアプリケーションで実行するシナリオなので、前の記事で作成したBusiness CentralやKIE Serverは不要です。

関連記事

Business Automation Manager Open Edition メモ - (1) 概要
Business Automation Manager Open Edition メモ - (2) KIE Server, Business Central 構成
Business Automation Manager Open Edition メモ - (3) Business Centralを使用したルール開発
Business Automation Manager Open Edition メモ - (4) KIEサーバー上のルール呼び出し
Business Automation Manager Open Edition メモ - (5) Embedded形態でのルール開発(DRL編)
Business Automation Manager Open Edition メモ - (6) Embedded形態でのルール開発(DMN編)
Business Automation Manager Open Edition メモ - (7) kogitoでのルール開発(スタンドアローン)
Business Automation Manager Open Edition メモ - (8) kogitoでのルール開発(OpenShiftへのデプロイ)

おことわり

当記事は2022年11月時点の情報をベースにしています。
最新版(V8.0)の以下のドキュメントをベースに進めようと思ったのですが、なぜだか肝心のDRLによる開発の章が抜け落ちております(過渡期でこの辺の整備がバタバタしている模様...)。
Developing decision services in IBM Business Automation Manager Open Editions

そのため、ここでは一旦旧バージョン(V7.13)のドキュメントをベースに進めていきたいと思います。
こちら: Developing decision services in Red Hat Decision Manager

全体像

いわゆる組み込み型(Embedded)の形態、つまり、ルール部分と、ルールを呼び出すアプリが一体となっている形態を動かすことを目指します。
image.png
開発、実行までの流れを確認することが目的なので、できるだけシンプルな形とします。ルール部分はDRLおよびExcelによる記述、アプリはStandAloneのJavaアプリケーションとします。

環境情報

今回はWindowsPC上で試します。以下のコンポーネントはセットアップ済みの想定です。

OS: Windows11

Java: OpenJDK 11

c:\>java -version
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

ビルド管理ツール: Maven 3.8.6

c:\>mvn -v
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: C:\x\apache-maven-3.8.6
Java version: 1.8.0_144, vendor: Oracle Corporation, runtime: C:\x\Java\jdk1.8.0_144\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

ルール開発ツール: VS Code 1.73.1
image.png

VS CodeのExtensionとしては以下のものを使用

Java,Maven関連
Extension Pack for Java
Debugger for Java

DRL関連
Drools VS Code Extension

※ここではWindows11環境での実行を試していますが、IBM BAM OE V8.0.1としてサポートしているOSはRHEL8, WindowsServer2016のみです。
参考: System Requirements for IBM Business Automation Manager Open Editions 8.0.1
Windows11でも動くだろうということで試しているものですのでご注意ください。また、droolsやkogitoなどオープンソースのプロジェクトでは基本的にRHELをベースに開発、テストが実施されているとのことで、Windows環境で実行する場合Windows固有の問題が発生することが多々あるようです。特に日本語を扱う必要がある場合は、実環境としてはLinuxでの利用を強くお勧めします。(もしくはMacの方がWindowsよりは問題が少ないと思われます。)

Mavenを使用したDRLでのルール開発、実行の流れ

基本的には以下を参考に、まずはDRLでルールを作成する流れを見ていきます。
Developing decision services in Red Hat Decision Manager - 20.2. Creating and executing DRL rules using Maven

事前準備

VS Code上で新規にワークスペースを作っておきます。

Javaアプリケーション用のMavenプロジェクト作成

コマンド・プロンプトを開き、ワークスペースのフォルダに移動して以下のコマンド実行します。

c:\y\VSCode_workspace\BAMOE_test01>mvn archetype:generate -DgroupId=com.sample.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.2.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.2.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.2.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: c:\y\VSCode_workspace\BAMOE_test01
[INFO] Parameter: package, Value: com.sample.app
[INFO] Parameter: groupId, Value: com.sample.app
[INFO] Parameter: artifactId, Value: my-app
[INFO] Parameter: packageName, Value: com.sample.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: c:\y\VSCode_workspace\BAMOE_test01\my-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  6.740 s
[INFO] Finished at: 2022-11-17T17:30:37+09:00
[INFO] ------------------------------------------------------------------------

以下のフォルダ、ファイルが作成されます。(Javaアプリ用のMavenプロジェクトが作成されました)

c:\y\VSCode_workspace\BAMOE_test01>tree my-app /f
フォルダー パスの一覧:  ボリューム Windows
ボリューム シリアル番号は 7E75-9120 です
C:\Y\VSCODE_WORKSPACE\BAMOE_TEST01\MY-APP
│  pom.xml
│
└─src
    ├─main
    │  └─java
    │      └─com
    │          └─sample
    │              └─app
    │                      App.java
    │
    └─test
        └─java
            └─com
                └─sample
                    └─app
                            AppTest.java

このmy-appをVS Codeのワークスペースに追加します。

"フォルダーを開く"を選択
image.png

mvnコマンドで作成されたmy-appフォルダを選択
image.png

上部に出ている"管理"をクリック
image.png

"信頼する"をクリック
image.png

VS CodeでMavenプロジェクトを扱う準備が整いました。
image.png

Factとなるデータオブジェクトの作成

ここで使用するサンプルは、賃金に関するルール判定を行うもののようで、Personというオブジェクトを作成し、そこに属性を設定していきます。
一般的にデータを扱うオブジェクトでよくみられるように、変数を設定し、それらのsetter/getterメソッドを定義するようにします。
サンプルのソースだと、変数としてはfirstName, LastName, hourlyRate, wage という4つのみが定義されていますが、ルール判定結果を格納するフィールドtestMessageを追加することにします。
パッケージはデフォルトのメインのアプリと同じcom.sample.appとします(配置するディレクトリとしてはmy-app/src/main/java/com/sample/app/)。

Person.javaソース
Person.java
package com.sample.app;

public class Person {

    private String firstName;
    private String lastName;
    private Integer hourlyRate;
    private Integer wage;
    private String testMessage;

    public String getFirstName() {
      return firstName;
    }

    public void setFirstName(String firstName) {
      this.firstName = firstName;
    }

    public String getLastName() {
      return lastName;
    }

    public void setLastName(String lastName) {
      this.lastName = lastName;
    }

    public Integer getHourlyRate() {
      return hourlyRate;
    }

    public void setHourlyRate(Integer hourlyRate) {
      this.hourlyRate = hourlyRate;
    }

    public Integer getWage(){
      return wage;
    }

    public void setWage(Integer wage){
      this.wage = wage;
    }

    public String getTestMessage(){
      return testMessage;
    }

    public void setTestMessage(String testMessage){
      this.testMessage = testMessage;
    }
  }

image.png

DRLによるルール作成

image.png

ようやく本丸であるルールを作成していきます。ここではDRLを使ってルールを開発していきます。サンプルではルールが1つだけしかなく面白くないので2つに増やしています。また、判定結果を標準出力に出しているだけで、呼び出し元で受け取る部分がなく、サンプルとしてイケてないので呼び出し元で結果を受け取れるように先に追加したフィールドに判定結果を格納するよう修正します。

ルール・ファイルはmy-app/src/main/resources/以下に、Javaと同じようにパッケージのディレクトリを掘って配置します。
ここでは、my-app/src/main/resources/com/sample/app/Wage.drlを作成します。

Wage.drlソース
Wage.drl
package com.sample.app;

import com.sample.app.Person;

dialect "java"

rule "Wage"
  when
    person : Person(hourlyRate * wage > 100)
    Person(name : firstName, surname : lastName)
  then
    person.setTestMessage(name + ", You are rich!");
    //System.out.println("====== Begin Rule Engine =====");
    //System.out.println("Hello " + name + " " + surname + "!");
    //System.out.println(person.getTestMessage());
    //System.out.println("====== End Rule Engine =====");
end

rule "Wage2"
  when
    person : Person(hourlyRate * wage <= 100)
    Person(name : firstName, surname : lastName)
  then
    person.setTestMessage(name + ", You are NOT rich!");
    //System.out.println("====== Rule Engine =====");
    //System.out.println("Hello " + name + " " + surname + "!");
    //System.out.println(person.getTestMessage());
    //System.out.println("====== End Rule Engine =====");
end

image.png

※補足
when - then で、ある条件に合致した場合にどういうアクションを取るか、というのを記述していきます。
1つ目のルールは、Personオブジェクトのインスタンスについて、hourlyRate * wage の値を計算して100より大きかったら、"You are rich!"という文字列をtestMessageにセットしています。
2つ目のルールは、同様にhourlyRate * wage の値を計算して100以下だったら"Your are NOT rich!"という文字列をtestMessageにセットしています。
hourlyRateって時給? wageって賃金? これ掛け算するってどういう意味?っていうのはちょっと何やってるのかわからんのですが...(わたくし英語センスないのでピンとこないだけかもしれないのですがネーミングまちがってんじゃね? hour * hourlyRate とか、hour * wage とかなら分かりやすいのだが。)
まぁ単純なサンプルなので細かい意味はおいておいて、2つの値を掛け算した結果を100を閾値としてそれより大きいか小さいかを判断する単純なルールを作っているというイメージです。結果は同じJavaオブジェクト(Fact)中のtestMessageに文字列として格納されることになります。
dialectとして"java"を指定しているので、Javaのコードが埋め込めます。上の例ではコメントアウトしていますが、thenの所にSystem.out.println()を埋めこめば、デバッグ情報としてどのルールが適用されたを確認しやすくなります。

管理ファイル作成

ルールファイルを含めたビルドを行うにあたって、以下の管理用のファイルを作成する必要があります。

kmodule.xml (KIE module descriptor)

kmodule.xmlというファイルを作成する必要があります。これはKIE module descriptorと呼ばれるもので、KIE baseなるものを定義するもののようです。この"KIE base"なるものの良い説明がなかなか見つからないのですが...

参考:
Drools Documentation - 4.1. KIE sessions

A KIE base is a repository that you define in the KIE module descriptor file (kmodule.xml) for your project and contains all in Drools, but does not contain any runtime data.

What Is Kie Base?

The KieBase is a repository of all the application’s knowledge definitions. It will contain rules, processes, functions, type models. The KieBase itself does not contain runtime data, instead sessions are created from the KieBase in which data can be inserted and process instances started.

KIE baseはルールやそれに関連するオブジェクトをまとめたリポジトリを意味するようで、ルールを利用するときの単位や特性(ステートフル/ステートレスなど)を決めるもののようです。とりあえずここではフワッと理解しておいて詳細はおいおい...。

my-app/src/main/resources/META-INF/以下にkmodule.xmlファイルを作成します。
とりあえず今回のサンプル実行ではデフォルトでよさそうなので、以下のようなファイルを作成します。

kmodule.xmlソース
kmodule.xml
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
</kmodule>

image.png

pom.xml

MavenでJavaプロジェクトの管理を行うために、pom.xmlに依存関係の設定等を追加していきます。

pom.xmlソース
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sample.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>

  <repositories>
    <repository>
      <id>jboss-ga-repository</id>
      <url>https://maven.repository.redhat.com/ga/</url>
    </repository>
  </repositories>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <drools.version>7.67.0.Final-redhat-00017</drools.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
      <version>${drools.version}</version>
    </dependency>
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-mvel</artifactId>
      <version>${drools.version}</version>
    </dependency>
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-api</artifactId>
      <version>${drools.version}</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

image.png

※補足
依存関係のあるモジュールは https://maven.repository.redhat.com/ga/ に提供されていますので、リポジトリの定義を追加しています。(2022年11月点ではリポジトリとしてはRedHatさんが提供しているものしか無いようなのでそちらを使います。この時点ではIBMさんは別のリポジトリを立ててはいないようで、モノは同じということでRedHatさんのリポジトリを使えばよいようです。)
参考: Learning IBM Business Automation Open Edition - Environment Setup - Maven

With IBM Business Automation Open Edition 8.0, the components are built around a Maven architecture predominantly. What this ultimately means is your workstation needs to be able to communicate with one to many different Maven Repositories. These labs will use two in particular, the Red Hat General Availability repository and Maven Central. You could easily replace the two repositories with a local environment one hosting the Maven dependencies as a mirror or based in a disconnected installation, but this is the easiest developer workflow for acquiring new dependencies. The reason we are pointing to the Red Hat Maven repository, at least in the short term, is that the builds for IBM Business Automation Open Edition 8.0 are being deployed there as they are the same binaries used within both the IBM and Red Hat products during the transition of Red Hat Process Automation Manager (RHPAM)/Red Hat Decision Manager (RHDM) from Red Hat into IBM Automation under the name of IBM Business Automation Open Edition 8.0 ( IBAMOE).

ちなみに、参考にしているRedHatのマニュアルの例だとpom.xmlのrepositoryのURLとしてhttpが指定されていますがそれだとビルド時に怒られたので、httpsに変更しています。

ルール実行のための依存関係として以下のモジュールを指定しています。

バージョンは7.xの最新のものを指定しています(7.67.0.Final-redhat-00017)。

pom.xmlを編集すると右下に以下のポップアップが出るのでYesをクリック。
image.png

ルールのテスト

テストコード作成

JUnitを使用してルール部分をテストするコードを書いていきます。

AppTest.javaソース
AppTest.java
package com.sample.app;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest 
    extends TestCase
{
    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest( String testName )
    {
        super( testName );
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite()
    {
        return new TestSuite( AppTest.class );
    }

    /**
     * Rigourous Test :-)
     */
    public void testApp()
    {
        // Load the KIE base:
        KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        // Set up the fact model:
        String strFirstName = "Tom";
        String strLastName = "Summers";
        int iHourlyLate = 10;
        int iWage = 8;

        Person p = new Person();
        p.setFirstName(strFirstName);
        p.setLastName(strLastName);
        p.setHourlyRate(iHourlyLate);
        p.setWage(iWage);

        // Insert the person into the session:
        kSession.insert(p);

        // Fire all rules:
        kSession.fireAllRules();
        kSession.dispose();

        System.out.println("***** testApp *****");
        System.out.println("testMessage: " + p.getTestMessage());
        System.out.println("******************");

        String expectedString = strFirstName + ", You are NOT rich!";
        assertTrue( p.getTestMessage().equals(expectedString) );

    }

    public void testApp2()
    {
        // Load the KIE base:
        KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        // Set up the fact model:
        String strFirstName = "Tom";
        String strLastName = "Summers";
        int iHourlyLate = 20;
        int iWage = 8;

        Person p = new Person();
        p.setFirstName(strFirstName);
        p.setLastName(strLastName);
        p.setHourlyRate(iHourlyLate);
        p.setWage(iWage);

        // Insert the person into the session:
        kSession.insert(p);

        // Fire all rules:
        kSession.fireAllRules();
        kSession.dispose();

        System.out.println("***** testApp2 *****");
        System.out.println("testMessage: " + p.getTestMessage());
        System.out.println("******************");

        String expectedString = strFirstName + ", You are rich!";
        assertTrue( p.getTestMessage().equals(expectedString) );
    }
}


image.png

※補足
今回ルールを2つ用意しているので、それぞれのルールに合致するテストケースを2つ設定して実行しています。本来であれば境界値の確認とか各種バリエーションを持たせたりすることになると思いますが、ここはオペレーションの流れを確認する目的なのでテストの中身は適当です。
KieSessionというオブジェクトを使って、FactとなるJavaオブジェクトをセットし(KieSession.insert())、ルールの実行(KieSession.fireAllRules()) を行っています。

テスト実施

左下のMAVENペインからtestを実行します。
image.png

ターミナルからテスト実行時のログが確認できます。

test時のログ
PS C:\y\VSCode_workspace\BAMOE_test01\my-app> & mvn test -f "c:\y\VSCode_workspace\BAMOE_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ my-app ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ my-app ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory c:\y\VSCode_workspace\BAMOE_test01\my-app\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ my-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ my-app ---
[INFO] Surefire report directory: c:\y\VSCode_workspace\BAMOE_test01\my-app\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.sample.app.AppTest
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
***** testApp *****
testMessage: Tom, You are NOT rich!
******************
***** testApp2 *****
testMessage: Tom, You are rich!
******************
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.381 sec

Results :

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.812 s
[INFO] Finished at: 2022-11-19T15:59:37+09:00
[INFO] ------------------------------------------------------------------------

image.png

ルール呼び出しJavaアプリケーション作成

image.png

ルールの確認ができたので、ルールを呼び出すアプリケーションを作成していきます(my-app/src/main/java/com/sample/app/App.java)。

App.javaソース
App.java
package com.sample.app;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class App 
{
    public static void main( String[] args )
    {
        // Parse arguments :
        String strFirstName = args[0];
        String strLatName = args[1];
        String strWage = args[2];
        String strHourlyRate = args[3];
        int iWage = Integer.parseInt(strWage);
        int iHourlyRate= Integer.parseInt(strHourlyRate);

        // Load the KIE base:
        KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        // Set up the fact model:
        Person p = new Person();
        p.setFirstName(strFirstName);
        p.setLastName(strLatName);
        p.setWage(iWage);
        p.setHourlyRate(iHourlyRate);
        
        // Insert the person into the session:
        kSession.insert(p);

        // Fire all rules:
        kSession.fireAllRules();
        kSession.dispose();

        System.out.println("***** App *****");
        System.out.println("testMessage: " + p.getTestMessage());
        System.out.println("***************");
    }
}

※補足
作法としてはテストコードで実施したものと基本的に同様です。ルール実行時に渡すFact(Javaオブジェクト)のフィールドはJavaアプリケーションの引数として渡すようにしています。結果は標準出力に出力するようにしています。

Javaアプリケーションのデバッグ

デバッガーを使ってデバッグしてみます。
左側のメニューからデバッグのアイコンを選んで、"launch.jsonファイルを作成します"をクリック。
image.png

my-appを選択
image.png

launch.jsonファイルの雛形ができるので、以下のようにargs要素を追加します(前の行の最後のカンマを忘れずに)。
image.png

左上のプルダウンからLaunch App(my-app)を選択します。
image.png

デバッグを開始
image.png

ブレークポイントを指定していないので、そのまま処理が流れます。結果はターミナルで確認できます。
image.png

適当なところにブレークポイントを指定して...
image.png

再度デバッグ実行してみます。ステップ実行など行えます。
image.png

jar作成

image.png

package実行時ログ
PS C:\y\VSCode_workspace\BAMOE_test01\my-app> & mvn package -f "c:\y\VSCode_workspace\BAMOE_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ my-app ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ my-app ---
[WARNING] Using platform encoding (MS932 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory c:\y\VSCode_workspace\BAMOE_test01\my-app\src\test\resources   
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ my-app ---
Results :

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ my-app ---
[INFO] Building jar: c:\y\VSCode_workspace\BAMOE_test01\my-app\target\my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  6.843 s
[INFO] Finished at: 2022-11-19T16:43:16+09:00
[INFO] ------------------------------------------------------------------------

targetディレクトリ下にmy-app-1.0-SNAPSHOT.jarが作成されました。
image.png

Mavenを使用したExcelでのルール開発、実行の流れ

上で作成したプロジェクトにルールを追加してみます。今度はDRLではなくExcelでルールを作成してみます。
ここでは、Business Centralでのルール作成の流れを確認する際に作成した、会員のランクに応じた割引率を決めるルールを作ってみます。

Factとなるデータオブジェクトの追加

先に作成したルールとは全く別のルールを作成する想定のため、新たにFactとなるデータオブジェクトをJavaのクラスとして作成します。

Loyalty.java
Loyalty.java
package com.sample.app;

public class Loyalty {

    private String rank;
    private double discountRate;
    private String testMessage;

    public String getRank() {
      return rank;
    }

    public void setRank(String rank) {
      this.rank = rank;
    }

    public double getDiscountRate() {
      return discountRate;
    }

    public void setDiscountRate(double discountRate) {
      this.discountRate = discountRate;
    }

    public String getTestMessage(){
      return testMessage;
    }

    public void setTestMessage(String testMessage){
      this.testMessage = testMessage;
    }
}

image.png

Excelによるルール作成

image.png

DRLで作成したルールと同じ場所(同じパッケージ)にExcelファイルを作成します(src/main/resouces/com/sample/app/loyalty.xlsx)。Excel上で決められた作法に従ってルールを定義していきます。

image.png

image.png

※補足
上の例だと、1~4行目がルールセットに関する定義です。
C1セルでパッケージ名を指定しています。
C2セルでルールで参照するJavaオブジェクト(Fact)をインポートします(複数ある場合はカンマ区切り)。
7行目~5行目がルールを表すテーブルです。
7行目は「RuleTable」という固定値 + ブランクをあけてテーブル名を指定します。
8行目は列の属性としてWHENに相当する部分には「CONDTION」を、THENに相当する部分には「ACTION」を指定します。
9行目は条件となるFactを指定しています。
10行目はWHENに相当する条件を指定しています。$1は12行目以降に示されている値に相当します。(12行目以降のセルにはカンマ区切りで複数の値を指定することが可能で、複数ある場合は順番に$1, $2,...と表現されます。値が1つしか含まれない場合は$1の代わりに$paramを使用することも可能。)
11行目には列のラベルを指定しています(12行目以降に指定する値の意味を分かりやすくするための任意の文字列)。
12行目から15行目には実際のルール(WHEN-THEN)で使用する具体的な値の組み合わせを指定しています。
セルの色は分かりやすいようにドキュメントの例にならって変えています。

Excelでのルールの記入方法の詳細は以下のドキュメントもご参照ください。

参考:
Developing decision services in IBM Business Automation Manager Open EditionsChapter - 35. Defining spreadsheet decision tables
Drools Documentation - 16.7.2. Defining spreadsheet decision tables

管理ファイルの編集

pom.xml

pom.xmlファイルに、以下の依存関係を追記します。

pom.xml抜粋
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-decisiontables</artifactId>
      <version>${drools.version}</version>
    </dependency>

Maven Repository: drools-decisiontables

変更を保存したら右下のポップアップのYesをクリック
image.png

ルールのテスト

テストコード追加

以下のテストコードを追加

AppTest.java
AppTest.java(抜粋)
    public void testApp3()
    {
        // Load the KIE base:
        KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        // Set up the fact model:
        String strRank = "シルバー";
        Loyalty loyalty = new Loyalty();
        loyalty.setRank(strRank);

        // Insert the person into the session:
        kSession.insert(loyalty);

        // Fire all rules:
        kSession.fireAllRules();
        kSession.dispose();

        System.out.println("***** testApp3 *****");
        System.out.println("Rank: " + strRank);
        System.out.println("DiscountRate: " + loyalty.getDiscountRate());
        System.out.println("******************");
        double expectedDiscountRate = 0.1;
        assertEquals(expectedDiscountRate, loyalty.getDiscountRate());

    }

image.png

※補足
テストの流れを確認する目的なので1ケースだけテストコードを追加しています。本来であれば各種テストケースを実行することになると思います。

テスト実施

テスト実行して正常にテストが完了することを確認します。
image.png

ルール呼び出しJavaアプリケーション改修

image.png

以下のように、追加したルールも使用するようアプリを改修します。

App.java
App.java
package com.sample.app;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class App 
{
    public static void main( String[] args )
    {
        // Parse arguments :
        String strFirstName = args[0];
        String strLatName = args[1];
        String strWage = args[2];
        String strHourlyRate = args[3];
        int iWage = Integer.parseInt(strWage);
        int iHourlyRate= Integer.parseInt(strHourlyRate);

        String strRank = args[4];
        

        // Load the KIE base:
        KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        // Set up the fact model:
        Person p = new Person();
        p.setFirstName(strFirstName);
        p.setLastName(strLatName);
        p.setWage(iWage);
        p.setHourlyRate(iHourlyRate);

        Loyalty l = new Loyalty();
        l.setRank(strRank);

        // Insert the person into the session:
        kSession.insert(p);
        kSession.insert(l);

        // Fire all rules:
        kSession.fireAllRules();
        kSession.dispose();

        System.out.println("***** Person *****");
        System.out.println("testMessage: " + p.getTestMessage());
        System.out.println("***************");

        System.out.println("***** Loyalty *****");
        System.out.println("Rank: " + strRank);
        System.out.println("DiscountRate: " + l.getDiscountRate());
        System.out.println("***************");

    }
}

image.png

Javaアプリケーションのデバッグ

引数を追加したのでデバッグ用のlaunch.jsonも変更してデバッグ実行
image.png

image.png

おまけ: エラーmemo

色々試しているときにMavenでのテスト実行時に以下のようなエラーが発生することがありました。

テスト時のログ
PS C:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app> & mvn clean -f "c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-app ---
[INFO] Deleting c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.256 s
[INFO] Finished at: 2022-12-15T13:49:36+09:00
[INFO] ------------------------------------------------------------------------
PS C:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app> & mvn clean -f "c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-app ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.178 s
[INFO] Finished at: 2022-12-15T13:49:56+09:00
[INFO] ------------------------------------------------------------------------
PS C:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app> & mvn compile -f "c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ my-app ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\target\classes      
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.238 s
[INFO] Finished at: 2022-12-15T13:50:02+09:00
[INFO] ------------------------------------------------------------------------
PS C:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app> & mvn test -f "c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\pom.xml"
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< com.sample.app:my-app >------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ my-app ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ my-app ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ my-app ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\target\test-classes  
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ my-app ---
[INFO] Surefire report directory: c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.sample.app.AppTest
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.38 sec <<< FAILURE!
testApp2(com.sample.app.AppTest)  Time elapsed: 0.376 sec  <<< ERROR!
java.lang.RuntimeException: Cannot find a default KieSession
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.findKieSessionModel(KieContainerImpl.java:546)
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:589)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:519)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:502)   
        at com.sample.app.AppTest.testApp2(AppTest.java:78)

testApp(com.sample.app.AppTest)  Time elapsed: 0 sec  <<< ERROR!
java.lang.RuntimeException: Cannot find a default KieSession
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.findKieSessionModel(KieContainerImpl.java:546)
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:589)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:519)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:502)   
        at com.sample.app.AppTest.testApp(AppTest.java:43)


Results :

Tests in error:
  testApp2(com.sample.app.AppTest): Cannot find a default KieSession
  testApp(com.sample.app.AppTest): Cannot find a default KieSession

Tests run: 2, Failures: 0, Errors: 2, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.035 s
[INFO] Finished at: 2022-12-15T13:50:27+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project my-app: There are test failures.
[ERROR]
[ERROR] Please refer to c:\y\VSCode_workspace\BAMOE_temp\bamoe_test01\my-app\target\surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:   
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

エラー箇所抜粋

java.lang.RuntimeException: Cannot find a default KieSession
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.findKieSessionModel(KieContainerImpl.java:546)
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:589)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:519)   
        at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:502)   
        at com.sample.app.AppTest.testApp2(AppTest.java:78)

ルールファイル(xxx.drl)を配置しているディレクトリ名がresoucesではなくresourceとtypoしていたため(末尾のsが抜けている状態)、ルールがうまく認識されずこのようなエラーになったものと思われます。
エラーの内容から原因が特定しにくく結構手間取ったので参考までにメモを残しておきます。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?