4.7.3. ルールユニットのアイデンティティーの競合
保護されたルールユニットを使用したルール実行のシナリオでは、1 つのルールが複数のルールユニットを保護することができます。同時に、複数のルールが 1 つのルールユニットを保護してから有効にすることもできます。このような 2 通りの保護シナリオでは、ルールユニットには、アイデンティティーの競合を避けるための明確に定義されたアイデンティティーが必要です。
デフォルトでは、ルールユニットのアイデンティティーはルールユニットクラス名で、RuleUnitExecutor によりシングルトンクラスとして処理されます。この識別動作は、RuleUnit インターフェイスの getUnitIdentity() のデフォルトメソッドにエンコードされています。
RuleUnit インターフェイスのデフォルトのアイデンティティーメソッド
default Identity getUnitIdentity() {
return new Identity( getClass() );
}
場合によっては、ルールユニット間のアイデンティティーの競合を避けるために、このデフォルトの識別動作をオーバーライドする必要があります。
たとえば、以下の RuleUnit クラスには、あらゆる種類のオブジェクトを許可する DataSource 定義が含まれています。
Unit0 ルールユニットクラスの例
public class Unit0 implements RuleUnit {
private DataSource<Object> input;
public DataSource<Object> getInput() {
return input;
}
}
このルールユニットには、2 つの条件 (OOPath 表記) に基づいて別のルールユニットを保護する、以下の DRL ルールが含まれています。
ルールユニットの DRL ルール GuardAgeCheck の例
package org.mypackage.myunit
unit Unit0
rule GuardAgeCheck
when
$i: /input#Integer
$s: /input#String
then
drools.guard( new AgeCheckUnit($i) );
drools.guard( new AgeCheckUnit($s.length()) );
end
保護された AgeCheckUnit ルールユニットは、一連の persons の年齢を検証します。AgeCheckUnit には、確認用の persons の DataSource の定義、検証用の minAge 変数、および結果を集計する List が含まれます。
AgeCheckUnit ルールユニットの例
public class AgeCheckUnit implements RuleUnit {
private final int minAge;
private DataSource<Person> persons;
private List<String> results;
public AgeCheckUnit( int minAge ) {
this.minAge = minAge;
}
public DataSource<Person> getPersons() {
return persons;
}
public int getMinAge() {
return minAge;
}
public List<String> getResults() {
return results;
}
}
AgeCheckUnit ルールユニットには、データソースの persons の検証を実行する以下の DRL ルールが含まれます。
ルールユニットの DRL ルール CheckAge の例
package org.mypackage.myunit
unit AgeCheckUnit
rule CheckAge
when
$p : /persons{ age > minAge }
then
results.add($p.getName() + ">" + minAge);
end
この例では、RuleUnitExecutor クラスを作成し、これらの 2 つのルールユニットが含まれる KIE ベースにクラスをバインドして、同じルールユニットの DataSource 定義を 2 つ作成します。
executor 定義とデータソース定義の例
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );
DataSource<Object> input = executor.newDataSource( "input" );
DataSource<Person> persons = executor.newDataSource( "persons",
new Person( "John", 42 ),
new Person( "Sally", 4 ) );
List<String> results = new ArrayList<>();
executor.bindVariable( "results", results );
一部のオブジェクトを入力データソースに挿入し、Unit0 ルールユニットを実行できるようになりました。
挿入されたオブジェクトを使用したルールユニット実行の例
ds.insert("test");
ds.insert(3);
ds.insert(4);
executor.run(Unit0.class);
実行結果一覧の例
[Sally>3, John>3]
この例では、AgeCheckUnit という名前のルールユニットはシングルトンクラスと見なされ、1 回のみ実行されます。この時、minAge 変数は 3 に設定されます。入力データソースに挿入された文字列 "test" および整数 4 の両方は、minAge 変数が 4 に設定された 2 回目の実行をトリガーする可能性もあります。しかし、同じアイデンティティーを持つ別のルールユニットがすでに評価されているため、2 回目の実行はありません。
このルールユニットのアイデンティティーの競合を解決するには、AgeCheckUnit クラスの getUnitIdentity() メソッドをオーバーライドして、ルールユニットアイデンティティーに minAge 変数も含めます。
getUnitIdentity() メソッドをオーバーライドする変更された AgeCheckUnit ルールユニット
public class AgeCheckUnit implements RuleUnit {
...
@Override
public Identity getUnitIdentity() {
return new Identity(getClass(), minAge);
}
}
このオーバーライドにより、以前のルールユニットの実行例は、以下の出力を生成します。
変更したルールユニットの実行結果一覧の例
[John>4, Sally>3, John>3]
minAge が 3 と 4 に設定されたルールユニットは、2 つの異なるルールユニットとみなされるようになり、両方とも実行されます。