4.7.2. ルールユニットの実行制御
一方のルールユニットの実行により、もう一方のルールユニットの開始がトリガーされるようにルールの実行を調整する必要がある場合に、ルールユニットは役に立ちます。
ルールユニットの実行制御を容易にするために、デシジョンエンジンは以下のルールユニットメソッドをサポートします。このメソッドは、DRL ルールアクションで使用して、ルールユニットの実行を調整することができます。
-
drools.run()
: 指定されたルールユニットクラスの実行をトリガーします。このメソッドでは、ルールユニットの実行を命令的に中断し、他の指定されたルールユニットを有効化します。 -
drools.guard()
: 関連付けられたルール条件が満たされるまで、指定されたルールユニットクラスが実行されないようにします (保護します)。このメソッドは、他の指定されたルールユニットの実行を宣言的にスケジュールします。デシジョンエンジンが、保護ルールの条件に対して少なくとも 1 つの一致をもたらす場合は、保護されたルールユニットが有効とみなされます。ルールユニットには、複数の保護ルールを含めることができます。
drools.run()
メソッドの例として、それぞれが指定されたルールユニットに属す以下の DRL ルールを検討してください。NotAdult
ルールは drools.run( AdultUnit.class )
メソッドを使用して AdultUnit
ルールユニットの実行をトリガーします。
drools.run()
を使用した制御された実行を含む DRL ルールの例
package org.mypackage.myunit unit AdultUnit rule Adult when Person(age >= 18, $name : name) from persons then System.out.println($name + " is adult"); end
package org.mypackage.myunit unit NotAdultUnit rule NotAdult when $p : Person(age < 18, $name : name) from persons then System.out.println($name + " is NOT adult"); modify($p) { setAge(18); } drools.run( AdultUnit.class ); end
この例では、これらのルールからビルドされた KIE ベースから作成された RuleUnitExecutor
クラスと、これにバインドされている persons
の DataSource
定義も使用します。
ルールエグゼキューターとデータソース定義の例
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase ); DataSource<Person> persons = executor.newDataSource( "persons", new Person( "John", 42 ), new Person( "Jane", 44 ), new Person( "Sally", 4 ) );
この例では、RuleUnitExecutor
クラスから DataSource
定義を直接作成し、これを単一ステートメントで "persons"
変数にバインドします。
例の実行コードは、関連する Person
ファクトが persons
データソースに挿入されると、以下の出力を生成します。
ルールユニット実行出力の例
Sally is NOT adult John is adult Jane is adult Sally is adult
NotAdult
ルールは、"Sally"
という人物の評価時に一致を検出します。この人物は 18 歳未満です。続いてこのルールは、この人物の年齢を 18
に変更し、drools.run( AdultUnit.class )
メソッドを使用して AdultUnit
ルールユニットの実行をトリガーします。AdultUnit
ルールユニットには、DataSource
定義の 3 人の persons
全員に対して実行可能となったルールが含まれています。
drools.guard()
メソッドの例として、以下の BoxOffice
クラスと BoxOfficeUnit
ルールユニットクラスを検討してください。
BoxOffice
クラスの例
public class BoxOffice { private boolean open; public BoxOffice( boolean open ) { this.open = open; } public boolean isOpen() { return open; } public void setOpen( boolean open ) { this.open = open; } }
BoxOfficeUnit
ルールユニットクラスの例
public class BoxOfficeUnit implements RuleUnit { private DataSource<BoxOffice> boxOffices; public DataSource<BoxOffice> getBoxOffices() { return boxOffices; } }
また、この例では、以下の TicketIssuerUnit
ルールユニットクラスを使用して、少なくとも 1 つのボックスオフィス (チケット売り場) が営業中である限り、ボックスオフィスでのイベントチケットの販売を続行します。このルールユニットは persons
および tickets
の DataSource
定義を使用します。
TicketIssuerUnit
ルールユニットクラスの例
public class TicketIssuerUnit implements RuleUnit { private DataSource<Person> persons; private DataSource<AdultTicket> tickets; private List<String> results; public TicketIssuerUnit() { } public TicketIssuerUnit( DataSource<Person> persons, DataSource<AdultTicket> tickets ) { this.persons = persons; this.tickets = tickets; } public DataSource<Person> getPersons() { return persons; } public DataSource<AdultTicket> getTickets() { return tickets; } public List<String> getResults() { return results; } }
BoxOfficeUnit
ルールユニットには、DRL ルール BoxOfficeIsOpen
が含まれます。これは、drools.guard( TicketIssuerUnit.class )
メソッドを使用して、イベントチケットを配布する TicketIssuerUnit
ルールユニットの実行を保護します。以下に DRL ルールの例を示します。
drools.guard()
を使用した制御された実行を含む DRL ルールの例
package org.mypackage.myunit; unit TicketIssuerUnit; rule IssueAdultTicket when $p: /persons[ age >= 18 ] then tickets.insert(new AdultTicket($p)); end rule RegisterAdultTicket when $t: /tickets then results.add( $t.getPerson().getName() ); end
package org.mypackage.myunit; unit BoxOfficeUnit; rule BoxOfficeIsOpen when $box: /boxOffices[ open ] then drools.guard( TicketIssuerUnit.class ); end
この例では、少なくとも 1 つのボックスオフィスが open
である限り、保護された TicketIssuerUnit
ルールユニットが有効なため、イベントチケットは配布されます。open
状態のボックスオフィスがなくなると、保護された TicketIssuerUnit
ルールユニットは実行されなくなります。
以下のクラスの例は、より完全なボックスオフィスのシナリオを説明します。
ボックスオフィスシナリオのクラスの例
DataSource<Person> persons = executor.newDataSource( "persons" ); DataSource<BoxOffice> boxOffices = executor.newDataSource( "boxOffices" ); DataSource<AdultTicket> tickets = executor.newDataSource( "tickets" ); List<String> list = new ArrayList<>(); executor.bindVariable( "results", list ); // Two box offices are open: BoxOffice office1 = new BoxOffice(true); FactHandle officeFH1 = boxOffices.insert( office1 ); BoxOffice office2 = new BoxOffice(true); FactHandle officeFH2 = boxOffices.insert( office2 ); persons.insert(new Person("John", 40)); // Execute `BoxOfficeIsOpen` rule, run `TicketIssuerUnit` rule unit, and execute `RegisterAdultTicket` rule: executor.run(BoxOfficeUnit.class); assertEquals( 1, list.size() ); assertEquals( "John", list.get(0) ); list.clear(); persons.insert(new Person("Matteo", 30)); // Execute `RegisterAdultTicket` rule: executor.run(BoxOfficeUnit.class); assertEquals( 1, list.size() ); assertEquals( "Matteo", list.get(0) ); list.clear(); // One box office is closed, the other is open: office1.setOpen(false); boxOffices.update(officeFH1, office1); persons.insert(new Person("Mark", 35)); executor.run(BoxOfficeUnit.class); assertEquals( 1, list.size() ); assertEquals( "Mark", list.get(0) ); list.clear(); // All box offices are closed: office2.setOpen(false); boxOffices.update(officeFH2, office2); // Guarding rule is no longer true. persons.insert(new Person("Edson", 35)); executor.run(BoxOfficeUnit.class); // No execution assertEquals( 0, list.size() );