Red Hat Decision Manager 7.0には、Decision Serverという機能があります。
ルールを書いてビルド後、この Decision Serverにデプロイすると、すぐにRESTのサービスとしてルールを実行することができる、というものです。
以前のバージョンにもあったのですが、7.0からは、Decision Serverを単体で使うこともできるようになり、便利になりました。
ということで、今回は、Decision Serverの構築方法と、ルールのデプロイ・実行方法について書きます。
注)記事内容はすべて個人の見解に基づくものであり、RedHat社の公式見解ではありません。
Decision Server構築に必要な環境を整える
Decision Serverは、APサーバ上にデプロイして使うものです。「.war」形式で提供されます。
ちなみに、warの名前は、kie-server.warです。なので、Kie Serverという言われ方をすることもあります。以前はExecution Serverと言ったりもしていました。全部同じものを指していると思ってください。
さて、まずはAPサーバが必要です。
Red Hat Decision Managaer 7.0において、Decision Serverをデプロイ可能な基盤は以下。
ここでは、JBoss EAP7.1を使いたいと思います。
ちなみに、Red Hat Decision Managerを正式にサブスクリプション契約すると、JBoss EAPも使うことができます。なので、よほどの事情がない限り、APサーバはJBoss EAPを選択しておけばよいです。
必要なもの
- JDK 1.8
- Red Hat JBoss EAP 7.1
- Red Hat Decision ManagerのDecision Server
EAPとDecision Serverについては、Red Hatのサイトからダウンロードする必要があります。
Red Hat Customer Portalからダウンロードが可能です。
上記サイトで「Request an Evaluation」というリンクがありますので、そこをクリックして、アカウント無い人は、個人アカウントでもなんでも作成することで、90日間の評価版がダウンロード出来ます。
評価版といっても、製品版と中身はまったく同じです。とりあえず使うだけならば、ここから自由にダウンロードが出来るようになっています。(一部製品を除く)
まずは、EAPを上記からダウンロードします。
バージョンは、7.1をダウンロードします。インストーラーからインストールしてもよいですが、以下をダウンロードして、解凍するだけでもOKです。
次に、Decision Serverをダウンロードして、EAP上にデプロイします。
同じく、Red Hat Customer Portalから、ダウンロードします。
Red Hat Decision Manager 7.0.1 Decision Server for All Supported EE7 Containersを選択します。
zip(rhdm-7.0.1.GA-kie-server-ee7.zip)がダウンロードされるので、解凍します。
解凍すると、kie-server.warというディレクトリがあるのがわかると思います。
Decision Serverのデプロイ
- rhdm-7.0.1.GA-kie-server-ee7/kie-server.warディレクトリを、EAP_HOME/standalone/deployments/ にコピーする
- rhdm-7.0.1.GA-kie-server-ee7/SecurityPolicyディレクトリを、EAP_HOME/bin に上書きする
- *EAP_HOME/standalone/deployments/*に、kie-server.war.dodeployというファイルを作成する。(中身は空でOK。このファイルがあると、EAP起動時にkie-server.warが自動デプロイされる)
以上です。
Decision Serverの起動
EAPを起動します。
が、その前にユーザを作っておきます。
ユーザを追加するシェルは、EAP_HOME/bin/add-user.shです。
$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role kie-server,admin
kie-serverとadminのロールを与える必要があります。
ここでは、USERNAME = redhat, PASSWORD = password1! として作成しました。
(パスワードは、8文字以上で、数値と記号をそれぞれ1つ以上入れる必要があります)
ユーザを追加後、EAPを起動します。
$ ./standalone.sh -c standalone-full.xml
起動が成功したら、Decision Serverにアクセスしてみましょう。
RESTfulのインターフェースで実行ができるところからであれば、確認が可能です。
とりあえず、ブラウザに以下を入力して実行してみましょう。
http://localhost:8080/kie-server/services/rest/server
これは、Decision Serverの情報を取得するREST APIです。
XML形式でレスポンスが表示されるはずです。"SUCCESS"とあれば、Decision Serverにアクセス出来ています。
curlコマンドから実行することも可能です。
curl -X GET "http://localhost:8080/kie-server/services/rest/server" -H "accept: application/json" -u <USERNAME>:<PASSWORD>
USERNAME
とPASSWORD
は、add-userで追加したユーザとパスワードをセット。
レスポンスで、"SUCCESS"が帰ってきていたら、Decision Serverにアクセス出来ています。
レスポンス例
{
"type" : "SUCCESS",
"msg" : "Kie Server info",
"result" : {
"kie-server-info" : {
"id" : "15ad5bfa-7532-3eea-940a-abbbbc89f1e8",
"version" : "7.5.0.Final-redhat-6",
"name" : "KieServer@/kie-server",
"location" : "http://localhost:8230/kie-server/services/rest/server",
"capabilities" : [ "KieServer", "BRM", "BPM", "CaseMgmt", "BPM-UI", "BRP", "DMN", "Swagger" ],
"messages" : [ {
"severity" : "INFO",
"timestamp" : {
"java.util.Date" : 1534320753784
},
"content" : [ "Server KieServerInfo{serverId='15ad5bfa-7532-3eea-940a-abbbbc89f1e8', version='7.5.0.Final-redhat-6', location='http://localhost:8230/kie-server/services/rest/server', capabilities=[KieServer, BRM, BPM, CaseMgmt, BPM-UI, BRP, DMN, Swagger]}started successfully at Wed Aug 15 17:12:33 JST 2018" ]
} ]
}
}
swagger
Decision Serverで使えるREST API一覧は、swaggerでリストされています。
Decision Serverが起動している状態で、以下にアクセスしてみてください。
swagger UIの画面が表示されます。
http://localhost:8080/kie-server/docs/
kie-server.warは、Red Hat Process Automation ManagementというBPM製品でも使われるもののため、Decision Managerでは使われないAPIもずらっとリストされます。
ルール実行で使うAPIは、
Kie Server::CORE、Decision Service::DMN、Rules Evalutaion::BRM
のあたりだけです。
追記:
kie-serverをDecision Serverとしてだけ使う場合、EAP起動時に、-Dorg.jbpm.server.ext.disabled=true
オプションを付与すると、BPM関連のAPIが除外されます。
EAPの起動時オプションは、EAP_HOME/bin/standalone.conf
を修正すればいちいち付けなくてよいです。
このswagger UIから、REST実行も可能になっています。
ルールをDecision Serverにデプロイする
Decision Serverでは、ルール実行単位、デシジョンサービス単位に、Kie Containerというのを作る必要がある。
まずは、Kie Containerを作るところから。
Kie Containerは、任意のIDを付け、どのルールパッケージを実行するのかを指定する必要がある。
ルールパッケージは、MavenのGAV(GroupID,ArtifactID,Version)を指定する。
事前に、ルールパッケージを作っておく必要があるわけだが、ここでは、
[Red Hat Decision Managerをとりあえず触ってみたい場合 -サンプルプロジェクト実行編-]
(https://qiita.com/Erina/items/85aaf496920ebaf58687)
で作成した、サンプルプロジェクトを使うことにします。
ただし、いくつか手をいれる必要があります。
修正点1 pom.xmlの修正
<dependencies>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-test</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
org.drools,org.jbpm等のjarは、Decision Server内のものを参照するため、dependencyのscopeを変更します。
修正点2 Messageファクトクラスを作成
サンプルプロジェクトでは、Messageファクトは、com.sample.DroolsTestクラス内のインナークラスとして定義されていましたが、独立したクラスとして定義します。
package com.sample;
public class Message {
@Override
public String toString() {
return "Message [message=" + message + ", status=" + status + "]";
}
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
また、上記により、Messageファクトのパッケージが変更になりますので、drlのimport文も修正します。
package com.sample
import com.sample.Message; ←ここを変更
以下略
サンプルプロジェクトを、Maven Installします。Decision Serverはデフォルトでは、ローカルの.m2ディレクトリを見に行きます。
サンプルプロジェクトのGAVは以下の通り。
<groupId>com.sample</groupId>
<artifactId>Sampleprj</artifactId>
<version>1.0.0-SNAPSHOT</version>
Kie ContainerIDはなんでもよいので、ここでは、testcon
とします。
Kie Containerを新規作成するAPIは、これです。
[PUT]/server/containers/{id}
idは、Kie ContainerID
bodyには、GAVを指定します。
{
"release-id": {
"group-id": "com.sample",
"artifact-id": "Sampleprj",
"version": "1.0.0-SNAPSHOT"
}
}
そして、REST実行。
curlコマンドからでもいいですが、swaggerUIからの実行が簡単です。
swaggerUIで、実行するAPIを検索して、「Try it out」をクリック。
必須パラメータと、body部を記入して、「Execute」を実行。リクエスト・レスポンスの形式は、xmlかjsonかを選択出来ます。
さて、ここで「Execute」を押して、Kie Containerの作成が成功すれば、サンプルプロジェクトのルールがデプロイされたことになります。Kie Containerは作成すると同時に開始します。
成功した場合、EAPのサーバログには以下のようなログが出されます。
23:38:06,768 INFO [org.kie.server.services.impl.KieServerImpl] (EJB default - 1) Container testcon (for release id com.sample:Sampleprj:1.0.0-SNAPSHOT) successfully started
Kie Containerの作成(ルールのデプロイ)に失敗する場合
Cannot find kbase, either it does not exist or there are multiple default kbases in kmodule.xml というエラーになる場合
23:29:07,431 ERROR [org.kie.server.services.jbpm.JbpmKieServerExtension] (default task-5) Error when creating container testcon by extension jBPM KIE Server extension: java.lang.RuntimeException: java.lang.IllegalStateException: Cannot find kbase, either it does not exist or there are multiple default kbases in kmodule.xml
これは、上のほうの追記にも書きましたが、EAP起動時オプションに、-Dorg.jbpm.server.ext.disabled=true
を付けたら、解消されました。
大量のWARNログが出る
Kie Container作ろうとすると、以下のようなWARNログが大量に出る、という場合は、ルールパッケージのdependencyに原因がある可能性が高い。
02:48:20,141 WARN [org.kie.server.services.drools.DroolsKieServerExtension] (EJB default - 1) Unexpected error while create instance of type org.dom4j.xpath.DefaultNamespaceContext due to Failed to link org/dom4j/xpath/DefaultNamespaceContext (Module "deployment.kie-server.war" from Service Module Loader): org/jaxen/NamespaceContext
02:48:20,189 WARN [org.kie.server.services.drools.DroolsKieServerExtension] (EJB default - 1) Unable to create instance of type org.jaxen.expr.iter.IterableFollowingSiblingAxis due to org.jaxen.expr.iter.IterableFollowingSiblingAxis
02:48:20,191 WARN [org.kie.server.services.drools.DroolsKieServerExtension] (EJB default - 1) Unable to create instance of type org.jaxen.expr.iter.IterableAncestorAxis due to org.jaxen.expr.iter.IterableAncestorAxis
サンプルプロジェクトのpom.xmlを見ると、org.droolsやorg.jbpmのjarを参照していると思います。
これらは、Decision Server上で提供されるため、build packageの際に含めないように、スコープをprovided
にする必要があります。
<dependencies>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-test</artifactId>
<version>${runtime.version}</version>
<scope>provided</scope> ← ここを追加すればOK
</dependency>
このWARNログが出た場合、Kie Containerの作成は成功したように見えても、その後のルール実行がうまくいかないので、注意が必要です。
ルールを実行する
さて、それでは、デプロイしたサンプルルールをRESTで実行してみたいと思います。
ルール実行のAPIは、以下です。
[POST]/server/containers/instances/{id}
idは、testcon
body部に、ルール実行に関するコマンドや、ルールに渡すデータ(ファクト)を指定します。
たとえば、こんな感じです。
{
"lookup": "ksession-rules",
"commands":[
{
"insert":{
"object":{
"com.sample.Message":{
"message": "Hello World",
"status": 0
}
}
}
},
{"fire-all-rules":""}
]
}
name | description |
---|---|
lookup | 実行するkie-session名を指定する。(kmodule.xmlで指定した値) |
commands | BatchExecutionCommandを渡す。 複数ある場合は、リスト形式で。 (ここでは、insertとfire-all-rulesの2つ) |
insert | InsertObjectCommand実行。 |
object | インサートするオブジェクト。 |
fire-all-rules | FireAllRulesCommand実行。 |
複数のファクトを渡したい場合は、insertを繰り返します。↓こんな感じです。
{"insert":
{"object":{"com.sample.Message":{
"message":"hello1",
"status":0
}
}
}
},
{"insert":
{"object":{"com.sample.Message":{
"message":"hello2",
"status":0
}
}
}
},
さて、ルール実行が成功すると、サンプルプロジェクトをローカルで実行した際と同様のログが、EAPのサーバログに出力されるはずです。
00:49:48,935 INFO [stdout] (default task-49) Hello World
00:49:48,936 INFO [stdout] (default task-49) Goodbye cruel world
ルール実行結果を返したい場合
ルール実行後のファクトを取得したい場合は、取得したいファクトにout-identifier
でキー名をつけます。
{
"lookup": "ksession-rules",
"commands":[
{
"insert":{
"object":{
"com.sample.Message":{
"message": "Hello World",
"status": 0
}
},
"out-identifier": "fact1"
}
},
{"fire-all-rules":""}
]
}
すると、レスポンスがこのようになります。
{
"type" : "SUCCESS",
"msg" : "Container testcon successfully called.",
"result" : {
"execution-results" : {
"results" : [ {
"value" : {"com.sample.Message":{
"message" : "Goodbye cruel world",
"status" : 1
}},
"key" : "fact1"
} ],
"facts" : [ {
"value" : {"org.drools.core.common.DefaultFactHandle":{
"external-form" : "0:1:279781204:279781204:2:DEFAULT:NON_TRAIT:com.sample.Message"
}},
"key" : "fact1"
} ]
}
}
}
ちなみに、このようなJSONをいちいち作成していられないので、もともとクライアント用のJavaクラスが用意されています。
このクライアントの使い方については、また別の投稿で。