はじめに
ODMを使ってルールを開発してそれを利用する流れを確認するために、ここでは製品提供のチュートリアルをなぞっていきたいと思います。ただ指示に従って作業していくだけだと何をやっているのか見失いがちなので、各操作について整理しながら進めていきます。
関連記事
IBM Operational Decision Manager メモ - (1) 概要、Linuxへのインストール
IBM Operational Decision Manager メモ - (2) ルール開発から実行までの流れ
IBM Operational Decision Manager メモ - (3) Decision Center利用の流れ
IBM Operational Decision Manager メモ - (4) Linux上での環境セットアップ
IBM Operational Decision Manager メモ - (5) z/OS上での環境セットアップ
IBM Operational Decision Manager メモ - (6) z/OS上でのルール呼び出し
IBM Operational Decision Manager メモ - (7) zODM環境補足
チュートリアルのシナリオ概要
今回実行するチュートリアルは以下に提供されるMiniloanと呼ばれる簡素化されたローン審査のアプリケーションを使います。
Getting started with business rules
このアプリケーションはLiberty上で稼働するWebアプリケーションの形式で提供されています(Servletをベースに実装されている)。
上のような画面が提供されていて、借り手の情報とローン申請内容を入力して「Validate Loan」ボタンを押すと、入力した内容から特定の判断基準に基づいてローン受け入れ可否を判定して結果を表示します。
シナリオとしては、Javaで実装されているアプリケーションから、ビジネス・ルールに相当するローン審査部分、つまり、「借り手の情報とローン申請内容からローン引き受け可否を判定する部分」を抽出して、ODMで管理させるようにアプリケーションを変更する、というのが大きな流れとなります。
ただ、チュートリアルを簡単に進めるために、提供されているアプリケーションの構造としては以下のように、埋め込みのロジックでローン可否を判断するフローと、ODM上のルールを使用してローン可否を判断するフローの両方を選択できるような作りになっています。
最初はODM上に管理されるルールが無い状態なので、埋め込みロジックを使ったフローでのみアプリケーションを動かすことができます。
ルールを作成してODM上にデプロイすれば、Javaの埋め込みコードの代わりにODM上のルールを呼び出すフローでアプリケーションを動かせるようになる、という寸法です。
このようにルールを外出しにしてあげれば可視化されて管理しやすいし、頻繁にルールを変更したい場合にもアプリそのものに手を入れなくても柔軟に変更できますよ、というお話です。
さて、チュートリアルでやることの大枠をイメージしたところで、手順に従って具体的に進めていきましょう。
チュートリアル実施
Getting started with business rules
事前準備
と、その前に、チュートリアルを実施するには先の記事でWindows側にインストールしたコンポーネントだけでは足りなかったので、追加でWindows側にコンポーネントをインストールします。
(最初の手順でSample Consoleを起動することになるのですが、これインストールしてなかった...)
先のインストール手順と同様、Installation Mangerからインストールを行います。以下の画面で「サンプルおよびチュートリアル」をチェックします。
この時、依存関係のある以下のコンポーネントもインストールする必要があるようです。
- Rule Executtion Server
- Rule Execution Server for Liberty profile
- Build Command
RESはLinuxのものを使う想定なのですが、なぜかその辺融通が効かないというか...。しょうがないので一緒に入れます。で、さらにLibertyも必要になるので、Libertyも事前にWindows上にインストールしておく必要があります(使わないんだけど...)。LibertyはODMのインストーラーに一緒に提供されている「wlp-base-embeddable-21.0.0.9.zip」を適当なディレクトリに展開しておけばよいだけです。
ここではc:\x\IBM\WebSphere\wlp-base-21.0.0.9_ODM811
に配置しておきます。こんな感じ。
Javaも必要になります。まぁそこは適当に。
もう一つ、追加でサンプルをインストールする際にDesigner用に使用するeclipseにアクセスするっぽいのですが、その時に日本語環境で起動するようになっていると以下のようなエラーで失敗します。
なので、eclipse.iniを編集して英語モードで起動するようオプションを指定しておく必要がありました。
具体的にはeclipse.iniの先頭に-nl en_US
を追加しておきます。
-nl en_US
-startup
plugins/org.eclipse.equinox.launcher_1.5.700.v20200207-2156.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.1200.v20200508-1552
-product
org.eclipse.epp.package.jee.product
-showsplash
org.eclipse.epp.package.common
--launcher.defaultAction
openFile
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.8
-Dosgi.instance.area.default=@user.home/eclipse-workspace
-XX:+UseG1GC
-XX:+UseStringDeduplication
--add-modules=ALL-SYSTEM
-Dosgi.requiredJavaVersion=1.8
-Dosgi.dataAreaRequiresExplicitInit=true
-Xms256m
-Xmx2048m
--add-modules=ALL-SYSTEM
で、Installation Managerに戻って、インストール進めます。
Javaのパス指定
Libertyのパス指定
ライセンス情報指定
これで、Sample Consoleというのがインストールされたので、Windowsのスタートメニューから起動してみます。
Sample Consoleとは言っても実体としては英語モード、パースペクティブ指定でEclipse起動してるだけっぽいんですけどね...
Starting the Miniloan web application
先の記事でLinuxに立てたSample Serverを起動します。そこにMiniloanアプリがデプロイされているので、それをブラウザからアクセスして動かしてみます。
デフォルトで指定されている値はそのまま、「Validate Loan」をクリックします。
判定結果として「Rejected」が返されました。
概要で示したように、Javaコードとして埋め込まれた判定ロジックを使ったフローを動かしてみた、ということです。
Task 1: Designing the main rule project in the decision service
Step 1: Starting Rule Designer and importing the getting started projects
Sample Console(Rule Designer)を起動して、Getting Started - Decision Server - start - Import projectsを選択します。
サンプルのプロジェクトがインポートされて、Ruleパースペクティブが開きます。
Step 2: Creating the main rule project for the decision service
"Decision Service Map"という作業手順のガイドのようなものが用意されており、基本的にはこのガイドに沿って作業を進めていけばよいようになっているようです。
まずは、このDecision Service Mapの最初のメニュー"Create main rule project"をクリックします。
これで枠となるプロジェクトが作成されます。
Step 3: Importing the XOM into your rule project
作成したプロジェクトに、XOM(Execution Object Model: "ゾム"と発音します)をインポートします。
補足: ルールを抽出して外出しにする場合、それは1つの"サービス"のように扱われます。すなわち判断基準の元となる情報を与えて(Input)、判断結果を受け取る(Output)ということになります。このInput/Outputとしてなんらかのデータをやりとりすることになりますが、そのデータ構造を表すものがXOMです。データ型を表すJava Bean(フィールドの定義とそれらをアクセスするgetter/setterメソッドが定義されたクラス)のようなものと捉えておけばよいと思います。今回はサンプルなので事前にJava用のXOMが提供されていますが、これはルールに対して受け渡しするデータに応じて作成することになります。
参考: Designing a BOM for a Java model
Decision Service Map の "Import XOM"をクリックします。
Java execution object modelを選択
miniloan-xomというJava XOMがサンプルとして提供されているので、それを選択します。
Step 4: Creating the business object model
ここでは、先にインポートしたXOMを元にしてBOM(Business Object Model: "ボム"と発音します)を作成していきます。
補足: ルールを作成する際にそのルールで扱われるデータ構造を表すオブジェクトがBOMです。XOMと位置づけが似ていますが、BOMはルール呼び出し元の言語(JavaやCOBOLなど)に依存しないODMの世界で管理されるオブジェクトです。アプリケーションが渡すデータはXOMを介してODM上のBOMにマッピングされるというイメージで捉えるのがよいと思います。BOM, XOMについては以下参照。
参考: Overview: BOM and execution object model (XOM)
Decision Service Map の "Create BOM"をクリックします。
名前を指定し、"Create a BOM entry from a XOM"を選択してNext
先ほどインポートしたXOMを選択し、Borrower, LoanにチェックしてNext
生成されたBOMからLoanをダブルクリックし、さらにMembers以下のaddToMessages(String)をダブルクリックします。
Member VerbalizationのところにあるTemplatesを確認してみます。
ODMではルールを記述する際にプログラミング言語ではなく、自然言語のような文言を使用することができます。上の例は、LoanのaddToMessageというメソッドを使うのに、"add xxx to the messages of xxx"というような形式で記述できることを意味しています。これは後ほど実際のルールを記述する際に使われます。
Step 5: Defining a decision operation
ここではDecision Operationというものを定義していきます。
補足: Decision Operationというのはルールを呼び出す単位を示すものです。先にも記載したように、ODM上に抽出したルールは"サービス"のように扱われます。すなわち、入出力データとして何を使用し、どのようなロジックを実行するかを定義することになりますが、それを"Decision Operation"として定義します。SOAPなどのWebサービスでいう所のWSDLのOperationに相当する、と理解すると分かりやすいと思います。
Decision Service Mapから、"Add decision operation"をクリックします。
deployment以下にDecision Operationの雛形が作成されます。
Decision Service Mapから"Go to operation map"をクリックします。
先ほど作成したDecision Operationを選択してOK
この後Decision Operationの中身を定義していくことになりますが、ここで実行するタスクがたくさんあるのでこのように別のMapでガイドが提供されています。
Step 6: Designing the operation signature
ここでは先に作成したオペレーションに対して入出力データを定義します。
Operation Mapから"Add variable set"をクリック
1行追加されるので、Nameに"borrower"を指定し、Typeとしては"miniloan.Borrower"を選択します。
Operation Mapから"Bind variablesをクリックします。
以下の矢印のように、先に追加したパラメータを、In/Out/In-Outのいずれかに割り当てます。ここでは、borrowerをInput Parametersの表にドラッグ&ドロップ、loanをInput-Output Parametersの表にドラッグ&ドロップします。
つまり、ルール呼び出しの際にborrowerとloanを渡して、結果としてloanを受け取るという定義をしていることになります。
ここまでの操作の整理
Task 2: Orchestrating the rules
ここから本丸である"ビジネス・ルール"をRule Designerを用いて実装していきます。つまりJavaでコーディングされていたローン可否判定ロジックを、ODM上で組み立てていくことになります。
ちなみにJavaで実装されていたコードを覗いてみるとこんな感じになっています。
参考: Javaによる判定ロジック
/*
* Copyright IBM Corp. 1987, 2021
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
**/
package com.ibm.odm.samples;
import java.text.MessageFormat;
import javax.json.Json;
import javax.json.JsonObject;
import miniloan.Borrower;
import miniloan.Loan;
public class JavaClient {
// Java Validation Part
public String validateWithJava(Loan loan, Borrower borrower) {
checkMaximumAmount(loan, borrower);
checkRepaymentAndScore(loan, borrower);
checkMinimumIncome(loan, borrower);
checkCreditScore(loan, borrower);
JsonObject response;
if (loan.isApproved()) {
response = Json.createObjectBuilder()
.add("decision", "Your loan is approved with a yearly repayment of " + loan.getYearlyRepayment())
.build();
} else {
response = Json.createObjectBuilder()
.add("decision", "Your loan is rejected")
.add("messages", loan.getMessages().toString())
.build();
}
JsonObject value = Json.createObjectBuilder()
.add("approved",loan.isApproved())
.add("response", response)
.build();
return value.toString();
}
/**
* check Repayment And Score
*/
private void checkRepaymentAndScore(Loan loan, Borrower borrower) {
if (borrower.getYearlyIncome() > 0) {
int val = loan.getYearlyRepayment() * 100
/ borrower.getYearlyIncome();
if ((val >= 0) && (val < 30) && (borrower.getCreditScore() >= 0)
&& (borrower.getCreditScore() < 200)) {
loan.addToMessages(Messages
.getString("debttoincometoohighcomparedtocreditscore"));
loan.reject();
}
if ((val >= 30) && (val < 45) && (borrower.getCreditScore() >= 0)
&& (borrower.getCreditScore() < 400)) {
loan.addToMessages(Messages
.getString("debttoincometoohighcomparedtocreditscore"));
loan.reject();
}
if ((val >= 45) && (val < 50) && (borrower.getCreditScore() >= 0)
&& (borrower.getCreditScore() < 600)) {
loan.addToMessages(Messages
.getString("debttoincometoohighcomparedtocreditscore"));
loan.reject();
}
if ((val >= 50) && (borrower.getCreditScore() >= 0)
&& (borrower.getCreditScore() < 800)) {
loan.addToMessages(Messages
.getString("debttoincometoohighcomparedtocreditscore"));
loan.reject();
}
}
}
/**
* Check Minimum Income
*/
private void checkMinimumIncome(Loan loan, Borrower borrower) {
if (loan.getYearlyRepayment() > (borrower.getYearlyIncome() * 0.3d)) {
loan.addToMessages(Messages.getString("toobigdebttoincomeratio"));
loan.reject();
}
}
/**
* Check Credit Score
*/
private void checkCreditScore(Loan loan, Borrower borrower) {
if (borrower.getCreditScore() < 200) {
loan.addToMessages(Messages.getString("creditscorebelow200"));
loan.reject();
}
}
/**
* Check Maximum Amount
*/
private void checkMaximumAmount(Loan loan, Borrower borrower) {
if (loan.getAmount() > 1000000) {
loan.addToMessages(Messages.getString("theloancannotexceed1000000"));
loan.reject();
}
}
protected static String escapeString(String str) {
return str.replaceAll("\"", "\\\\\"").replaceAll("\n", "");
}
protected static String formatTrace(String ruleName, String taskName) {
String format = Messages.getString("messagefiredinruletask");
Object[] arguments = { ruleName, taskName };
return MessageFormat.format(format, arguments);
}
}
今回実装したいロジックでは、いくつかの条件の組み合わせでAccept or Rejectを判定する訳ですが、フローとしては大きく2種類の判断ロジックに分かれます。
(1) ローン額の上限値判定
(2) 借り手の情報(収入やクレジットスコアなど)とローン額の組み合わせから判定
以降の手順では(1)の部分を"Validation"、(2)の部分を"Eligibility"と名付けて各種オブジェクトを作成していくことになります。
大きな流れとしては、
(1)で絶対的なローン上限値を超えているかどうかの判定を行い、越えていればReject、越えていなければ(2)の判定に進む
(2)で各種情報をの組み合わせから詳細な条件判定を行う
という感じです。
Step 1: Creating rule packages
まずRule Packageというものを作ります。
補足: Rule Packageというのは、個々のビジネス・ルールを収める箱のようなものです。Javaでいう所の関連するクラスをまとめるPackageのようなものと理解すればよいでしょう。つまり関連性のある具体的なルールをまとめる単位ということになります。
ここでは先に示した2つの分類に従って、"validation", "eligibility"という2つのRule Packageを作成します。
Operation Mapから"Add rule package"をクリック。
Package名に"validation"を指定してFinish
同様に"eligibility"というRule Packageも作成します。
結果として以下の様に2つのパッケージが作成されます。
ここでは一旦パッケージだけ作っておき、実際のルールそのものの作成は後回しにします。
Step 2: Creating the ruleflow diagram
ここではRuleflowというものを作ります。
補足: 抽出したルールは1つの"サービス"のように扱われることになりますが、サービスとして動くメインのフローを定義するためのものが"Ruleflow"です。ローン可否判断をするにはいくつかのルール(条件判定)を組み合わせて最終的な判断を行うことになりますが、"Ruleflow"ではそれらのルールをどういう順番でどういう風に組み合わせるか、という大きな流れを定義することになります。
Operation Mapから"Add ruleflow"をクリック。
Ruleflowが作成されて、エディターが開きます(白紙状態)。
このエディター上で、グラフィカルにフローを作成することができます。
start/end それぞれのノードをドラッグ&ドロップします。
Step 3: Defining rule tasks
rule taskをクリックしてProperties viewにてIDを"validation"に変更しAlgorithm: Fastpathを選択します。
Properties viewのRule Selectionタブで、Editをクリック。
先に定義したvalidationパッケージを選択します。
これで、このノードにvalidationパッケージが紐づけされました。
同様に、eligibliltyというノードをエディター上に作成し、elibibilityパッケージを紐づけます。
"Layout All Nodes"というアイコンをクリックするときれいに配置が整います。
Step 4: Defining the main transition
validation - eligibility間の矢印をクリックしてProperties viewにて、以下のように設定します。
これは、validationノードの結果として「'the loan' is approved」と判断された場合次のeligibilityノードに進む、ということを表しています(それ以外の場合はendノードに分岐)。
Step 5: Defining the final action
最後に、endノードをクリックして、Properties viewにて、以下の様な設定を行います。(ここでは最後に判定結果を出力させるステートメントを追記しています。)
ここまでで、先に示した全体のフローが定義できたことになります。
(1)validationでの判定
=> OKだったら(2)eligiblityでの判定
=> NGだったら終了
※validation, eligibilityの箇所で具体的にどのような判定を行うかというのはまだ実装していないので、後のステップで作っていくことになります。
Step 6: Binding the ruleflow
上で作成したRuleflowを、Task1で作成したDecision Operationに紐づけます。
補足: 繰り返しになりますが、抽出されたルールは"サービス"のように扱われることになり、その呼び出し単位はDecision Operationとして定義されます。Task1で作成したDecision Operation "my operation"には、入出力データの定義は行いましたが具体的に何のロジックを実行するか、という指定はしていませんでした。Task2では実行すべきメインのロジックであるRuleflowを作成したので、これをDecision Operation "my operation"に紐づけてあげます。
Operation Mapから"Bind ruleflow"をクリック。
Decision Operation Overviewの画面が開くので、Ruleflowの欄で"Use main ruleflow"を選択し、""のリンクをクリックします。
ここまでの操作の整理
Task2では、以下の(6)~(8)までを実施したイメージ。
ここまでで、どういうフローをどのように動かすかという大枠がやっとできた感じです。ここに個別の具体的な細かいルールを埋め込んでいく必要があります。その辺は次のTaskで...
Task 3: Authoring rules
ここでは具体的な判断ロジック(JavaやCOBOLでいうところのif文/case文相当のロジック)を作っていくことになります。
Step 1: Creating an action rule
先に作成したRule Package(valication/eligibility)以下に、action ruleというものを作っていきます。
補足: ここでは個別の判断ロジックを作っていくことになりますが、その記述方法には主に2種類の方法があります。
1つは"action rule"と呼ばれるオブジェクトを使う方法です。これはJavaやCOBOLのif文に近いイメージで実装する方法ですが、もう少し自然言語っぽく条件を記述することができます。比較的単純な判定を行う場合に適しています。
もう1つは"decision table"と呼ばれるオブジェクトを使う方法です。これは表のイメージで実装する方法で、複数のパラメーターの複雑な組み合わせで判定を行う場合に適しています。
Operation Mapから"Add action rule"をクリック。
まずvalidationパッケージにローン額の上限値の判定を行うための"maximum amount"というaction ruleを作成します。
Packageからvalidationを選択してNameに"maximum amount"を指定してFinish
※デフォルトではTypeとして"ActionRule"が指定されていますのでそのままにしておきます。
"maximum amount"というaction ruleが作成されてエディター(右側部分)が開きます。
Step 2: Completing the action rule
エディターの"Content"の欄に判定ロジックを記述していくことになります。
まず、if
と入力してpaceを押すとステートメント候補が表示されるのでそこから選択することができます(いわゆるコンテンツ・アシスト機能が使えます)。
コンテンツ・アシスト機能を使いながら以下のように記入していき、最後にセミコロンを記入します。
改行してCtrl+Spaceで候補を出し、reject <a loan>
を選択
最後にセミコロンを記入。
英語モードなのでちょっとありがたみが分かりにくいですが、このように自然言語っぽく条件が記述できます。
つまりここでは、「loanのamount(つまりローン額)が$1,000,000を超えていた場合、messagesに"The loan cannnot exceed 1,000,000"という文字列をセットして、Rejectつまり"不可"と判断する」というルールが定義できたことになります。
※これって実はCOBOL構文に近いんだよなぁ。元々COBOLは英語の構文に近い形で書けるように作られた言語なので...
サンプルは英語モードで実行する必要があるので英語モードにしてますが、日本語モードにすれば日本語での記述もできるはず。
validation部分のルールはこれで完了です。
Step 3: Importing remaining rules
次にeligiblility部分のルールを実装していきます。
ここは結構複雑なルールの組み合わせなので、ここでは一から作るのではなく事前に定義を作ってくれているものをインポートすることで代替します。
メニューからFile-Importを選択し、General-File Systemを選択してNext
From directoryで<InstallDir>/gettingstarted/DecisionServer/answer/Miniloan Service
を選択
左側の画面でMiniloan Service-rules-eligilibityを選択し、右側のファイル一覧から.rulepackage以外をチェック
Into folderでmy decision service
を選択
OptionsでOverwrite existing resources without warning
にチェック
これで、eligibility関連のルールがインポートされました。
Step 4: Viewing the imported rules
eligibilityパッケージとしては以下の3つのルールが定義されています。
(1) minimum credit score (action rule)
(2) minimum income (action rule)
(3) repayment and score (decision table)
補足: (1)、(2)は記述内容を見ればまぁやってることは分かりやすいと思うので解説は省略します。decision tableとして記述されている(3)のルールについて補足します。これは、"debt to income"と"credit score"の組み合わせでローン可否判定をするための表です。"debt to income"は、借り手の年収における返済額の割合を示しています。"credit score"は入力されたcredit scoreの数値そのものです。例えば表の1行目に注目すると"debt to income"が0%~30%で、かつ、credit scoreが0~200の場合はReject(不可)と判断されます。このように表の形でルールを記述することで直感的にも分かりやすく、抜け漏れや重複のリスクも軽減されます。
先に作成したRuleflow "miniloan" を見てみます。
eligibilityのノードを選択してProperties viewのRule Selectionタブを確認すると、eligibilityパッケージ下にインポートされた3つのルールがリストされていることが確認できます。
補足: ここで、この3つのルールについてはそれぞれ独立性が担保されている、つまり相互に依存関係が無いということに注意してください。ローン可否判定の基本的なロジックとしては初期値としてはapproved=true(許可)となっていて、いずれかのReject条件に合致した場合にステータスが上書きされる(approved=false)、というやり方でルールを実装しています。そのためこれら複数のルールの順序性は関係無く実行できることになります。
デフォルトではRuleflow中のノードの実行アルゴリズムは"Fastpath"になっています。
これは今回のルールのようにお互い干渉しない前提のルールの場合には利用可能ですが、例えばrule1のロジックで変更した値をベースにrule2のロジックで別の判断を行う、といった場合には意図した結果にならない場合があります。そのような場合、別のアルゴリズムを選択する必要がありますのでご注意ください。詳細は以下の辺りも参考に...
参考: Engine execution modes
ここまでの操作の整理
Task3では、以下の(9)~(10)までを実施したイメージ。
※青字はDecision Service Map, Operation Map のメニューにある操作
これで一通りルールの実装は完了です。
Task 4: Testing and debugging
ここでは、作成したルールをRule Designer上でテスト/デバッグしてみます。
Step 1: Creating a run configuration
EclipseのメニューからRun - Run Configurations... を選択
Decision Operationを右クリックしてNew Configurationを選択
適当な名前をつけて、テストするDecision Operationを選択します。
Parameters & Argumentsタブでルールのテスト時に与えるパラメーターを設定します。
表のborrowerを選択してEdit Valueをクリック
Expression valueを選択し、new miniloan.Borrower("Joe", 600, 8000)
を入力してOK
同様にloanについてもEdit Valueを行い、new miniloan.Loan(50000, 240, 0.05)
を指定します。
最終的には以下のようになるので、ApplyをしてRun。
すると、指定した値を元にルールが動いて結果がConsoleに返されました。
Step 2: Inserting a breakpoint
Ruleflowを開いてeligibilityノードを右クリックし、Toggle Breakpointを選択
ブレークポイントが設定されたことを示す、丸印が表示されます。
もう一つ、eligibilityパッケージに含まれるminimum incomeというruleを開き、Contentの4行目の左端の空白部分を右クリックしToggle Breakpointを選択
ブレークポイントが設定されたことを示す、丸印が表示されます。
Step 3: Running the debugger
今度はデバッグモードでテスト実行します。
EclipseのメニューからRun - Debug Configurations...を選択
以下のポップアップが出るのでSwitchをクリックしてDebugパースペクティブに切り替えます。
ブレークポイントで処理がストップして状況を確認できるようになります。
あとはJavaアプリなどと同じように次のブレークポイントまで進めたり、変数の値を確認したりできます。
最後まで進めると先ほどのテストと同じように結果がConsoleに表示されます。
ここまでの操作の整理
Task4では、以下の(11)~(12)までを実施したイメージ。
※青字はDecision Service Map, Operation Map のメニューにある操作
Task 5: Deploying and running your ruleset
Rule Designer上でルールの作成、テストまで済んだので、次はこれを実際の稼働環境であるRES(Rule Execution Server)にデプロイして動かしてみます。
事前確認
もう一度MiniloanのWebアプリにアクセスします。ここでは一応Use rulesにチェックを入れてODM上のルールを使うフローを動かしてみます。
まだルールをRES上にデプロイしていないので、そんなの無いよってエラーになっています。このエラーは想定内。
Step 1: Creating a deployment configuration
Rule Designer上で"Deployment Configuration"というものを作成し、デプロイを行うための構成を行います(どのRESに何をデプロイするか、というのを設定していきます)。
Decision Service Mapから"Create deployment configuration"をクリック。
Deployment configurationのガラが作成され、エディターが開きます。
Decision Operationsタブで、Configured Decision Operationsの下の「+」ボタンをクリック。
デプロイ対象のDecision OperationをチェックしてFinish
Step 2: Enabling ruleset monitoring
監視用のパラメーターを設定します。
追加したDecision Operatorを選択し、Ruleset Properties欄の「+」ボタンをクリック。
Name: ruleset.bom.enabled, Value: trueをセット
同様に、monitoring.enabled、ruleset.sequential.trace.enabled を追加し、いずれもtrueをセットします。
結果こんな感じになります。
Step 3: Deploying the ruleset
Ruleset Version Policy欄で、Increment minor version numbersを選択
Create a Rule Executeion Server connectionを選択してNext
Test Connectionボタンをクリックして、接続が成功することを確認し、Finish
設定を保存し、OverviewタブのProceed to RuleApp deploymentのリンクをクリックします。
Step 4: Viewing the deployed RuleApp
きちんとデプロイされたかどうか、RES側を覗いて確認してみます。
エクスプローラータブから、my_operationが使用可能になっていることが確認できました。プロパティーも正しく設定されています。
Step 5: Testing the HTDS description file
RES上のRuleAppを簡易的にテストできる機能がRES Consoleから使えるようなのでテストしてみます。
対象のルールセットを開いて、"HTDS記述ファイルの取得"をクリック
プロトコル・タイプ: REST、フォーマット:OpenAPI-JSON を選択し、テストをクリック
以下のような画面になるので、入力データをJSON形式で指定して"要求の実行"をクリック
RES上でルールの単体テストが実施できました。
Step 6: Running the Miniloan web application with rules
それでは、いよいよ最終目的であるminiloanのWebアプリから、先ほどデプロイしたRES上のルール呼び出しを実行してみます。
ブラウザからminiloanのWebアプリにアクセスし、Use rulesにチェックを入れ、RESの接続情報を設定して"Validate Loan"実行!
すると今度はきちんとRES上のルールが実行されてその結果が画面に返されました!!!
これでルールの外出しが完了しました!
ちなみにWebアプリケーション(Java)からRES上のルール呼び出しは、REST(HTTP/JSON)でアクセスするコードに置き換わることになります。
参考: ルール呼び出し部分の実装
/*
* Copyright IBM Corp. 1987, 2021
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
**/
package com.ibm.odm.samples;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class RESTJSONJavaClient {
/**
* Get a closeable HTTP client
*
* @return closeable HTTP client
* @throws Exception
*/
public static synchronized CloseableHttpClient getClient() throws Exception {
CloseableHttpClient client = HttpClients.createDefault();
return client;
}
/*
* Return credentials for user id and password
*/
private static String getBase64Credentials(String userId,String userPassword)
{
String authstring = userId + ":" + userPassword;
String encoded = Base64.encodeBase64String(authstring.getBytes());
return encoded;
}
/**
* Execute a ruleset with the supplied payload to a specified endpoint URI using the
* supplied user id and password for authentication.
*
* @param endpointURI
* @param userId
* @param userPassword
* @param payload
* @return ruleset execution response as String
* @throws Exception
*/
public static String executeRulesetWithJSONPayload(String endpointURI, String userId,
String userPassword, String payload) throws Exception {
String result = "";
String errorMessage = "An error occurred when invoking the decision service at "
+ endpointURI
+ ":\n";
HttpPost httpPost = null;
CloseableHttpClient client = getClient();
try {
try {
httpPost = new HttpPost(endpointURI);
} catch (Exception e) {
throw new RuntimeException(errorMessage
+ e.getClass().getName() + ": " + e.getMessage());
}
// Authorization header required when accessing from internet
String encodedValue = getBase64Credentials(userId, userPassword);
String authorization = "Basic " + encodedValue;
httpPost.addHeader("Authorization", authorization);
// Add content type to header
httpPost.addHeader("Content-Type", "application/json");
CloseableHttpResponse response = null;
try {
// Set entity to payload for execution
httpPost.setEntity(new StringEntity(payload));
// Execute Post method using the HTTP client and retrieve response
try {
response = client.execute(httpPost);
} catch (Exception e) {
throw new RuntimeException(errorMessage
+ e.getClass().getName() + ": " + e.getMessage());
}
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
int statusCode = response.getStatusLine().getStatusCode();
System.err.println("Status Code: " + statusCode);
System.err.println("Status Line: " + response.getStatusLine());
String responseEntity = EntityUtils.toString(response.getEntity());
System.err.println("Response Entity: " + responseEntity);
if (statusCode == 302) {
throw new RuntimeException(errorMessage
+ "Unauthorized. Check your user ID and password.");
}
else {
throw new RuntimeException(errorMessage
+ response.getStatusLine() + ": " + responseEntity);
}
} else {
result = EntityUtils.toString(response.getEntity());
System.out.println("Result: " + result);
}
} finally {
if (response != null) {
response.close();
}
}
} finally {
client.close();
}
return result;
}
}
ここまでの操作の整理
Task5では、以下の(13)~(16)までを実施したイメージ。
※青字はDecision Service Map, Operation Map のメニューにある操作
Task 6: Monitoring
ここまでで一通りルールを外出しにする手順は確認できましたが、ODMを使うと実行されたルールの稼働状況も簡単にモニターできるようなので見てみます。
Step 1: Running Rule Execution Server diagnostics
前の手順で実施済みなので割愛
Step 2: Viewing statistics on deployed RuleApps
RESコンソールのExplorerから対象のオペレーションを選択し、"統計情報の表示"をクリック
このルールが実行された回数、平均処理時間などの情報が確認できます。
Step 3: Searching for past transactions in Decision Warehouse
意思決定ウェアハウスタブを選択し、そのまま検索をクリック
※検索条件指定していないので全検索になります。まだほとんどルール実行していないのでこれでもよいですが、必要に応じて条件を絞り込めます。
Step 4: Viewing the run rules
一覧表示された表から意思決定トレース列のリンクをクリックすると詳細が確認できます。
各ルール実行がどういうフローを辿って判断されたかというのが、このように確認できます。
Task 7: Publishing to Decision Center
ここまでは、Windows上のRule Designer(Eclipse)上でルールを開発してそれを実行環境であるRESにデプロイして動かすという流れをやってみました。一度このようにルールを作成すると、Decision Centerでルールを管理/メンテナンスすることができます。作成したルールをDecision Centerで管理するようにしておくと、ブラウザのインターフェースを使ってルールのメンテナンスが行えるため、開発者ではない業務よりのユーザーでもルールの変更/リリースのような操作が容易に行えるようになります。
ここでは、上で作成したルールをDecision Centerに公開するところをやってみます。
Step 1: Publishing the rule project to Decision Center
Linux上のSample Server(RESとDecision Center兼用)が上がっていて、ブラウザからDecision Centerにアクセスできることを確認しておきます。
Rule Designerで、Rule Explorer viewから対象のプロジェクトを右クリック - Decision Centerを選択
Connetボタンを押して接続が正常に行えることを確認します。OKであればNext。
Use Decision Governance FrameworkにチェックをしてFinixh
YesをクリックしてTeam Synchronizingパースペクティブを開きます。
Decision Centerにプロジェクトが公開され、Decision Centerとの同期を管理する画面が開きます。
これでDecision Centerへの公開は完了です。
Step 2: Exploring the rule project in Decision Center
ブラウザからDecision Centerにアクセスして公開したプロジェクトを確認してみます。
Decision Centerにログインしてライブラリータブを見ると、先ほど公開した"my decision service"が表示されています。
意思決定成果物タブで"すべてのプロジェクト"をクリックし、"すべてのタイプ"にチェックを入れて適用します。
すべてのタイプのオブジェクトが表示されるので、validation - maximum amount を選択します。
action rule の中身を確認することができます。(編集も可)
前に戻ってeligibility - repayment and score を選択します。
decision table の中身を確認することができます。(編集も可)
このように、ブラウザのUIを使ってルールのメンテナンスなどを行うことができます。
※Decision Centerについては別のチュートリアルがあるのでそちらを実施する予定