前回は状態機械を持ったエンティティを状態遷移させてみました。
今回は状態機械にアクションを設定し、状態遷移に伴うアクションの動作を確認します。
モデル
モデルは基本的には前回のものと同じですが、各アクションにアクションが実行されたことを示す文字列をコンソールに表示するようにしました。
アクションにはKaleidox言語を設定することができます。そこで、各アクションではKaledioxのprint関数を呼び出すようになっています。
- * event
- event=[{
- name="confirm"
- },{
- name="reject"
- },{
- name="delivered"
- },{
- name="cancel"
- },{
- name="suspend"
- },{
- name="resume"
- }]
- * entity
- ** salesorder
- *** features
- table=salesorder
- *** attributes
- | Name | Type | Multiplicity |
- |------+-------+--------------|
- | id | token | 1 |
- | price| int | 1 |
- *** statemachines
- **** status
- state=[{
- name=INIT
- transition=[{
- to=running
- effect="println \"transition from INIT to running\""
- }]
- entry="println \"entry INIT\""
- exit="println \"exit INIT\""
- do.entry="println \"do.entry INIT\""
- do.exit="println \"do.exit INIT\""
- },{
- name=canceled
- transition=[{
- to=FINAL
- effect="println \"transition from canceled to FINAL\""
- }]
- entry="println \"entry canceled\""
- exit="println \"exit canceled\""
- do.entry="println \"do.entry canceled\""
- do.exit="println \"do.exit canceled\""
- },{
- name=suspended
- transition=[{
- guard=resume
- to=HISTORY
- effect="println \"transition from suspended to HISTORY\""
- }]
- entry="println \"entry suspended\""
- exit="println \"exit suspended\""
- do.entry="println \"do.entry suspended\""
- do.exit="println \"do.exit suspended\""
- }]
- statemachine=[{
- name="running"
- state=[{
- name=INIT
- transition=[{
- to=applying
- effect="println \"transition from running.INIT to running.applying\""
- }]
- entry="println \"entry running.INIT\""
- exit="println \"exit running.INIT\""
- do.entry="println \"do.entry running.INIT\""
- do.exit="println \"do.exit running.INIT\""
- },
- {
- name=applying
- transition=[{
- to=confirming,
- effect="println \"transition from running.applying to running.confirming\""
- }]
- entry="println \"entry running.applying\""
- exit="println \"exit running.applying\""
- do.entry="println \"do.entry running.applying\""
- do.exit="println \"do.exit running.applying\""
- },{
- name=confirming
- transition=[{
- guard=confirm
- to=confirmed
- effect="println \"transition from running.confirming to running.confirmed\""
- },{
- guard=reject
- to=rejected
- effect="println \"transition from running.confirming to running.rejected\""
- }]
- entry="println \"entry running.confirming\""
- exit="println \"exit running.confirming\""
- do.entry="println \"do.entry running.confirming\""
- do.exit="println \"do.exit running.confirming\""
- },{
- name=confirmed
- transition=[{
- to=delivering
- effect="println \"transition from running.confirmed to running.delivering\""
- }]
- entry="println \"entry running.confirmed\""
- exit="println \"exit running.confirmed\""
- do.entry="println \"do.entry running.confirmed\""
- do.exit="println \"do.exit running.confirmed\""
- },{
- name=rejected
- transition=[{
- to=FINAL
- effect="println \"transition from running.rejected to FINAL\""
- }]
- entry="println \"entry running.rejected\""
- exit="println \"exit running.rejected\""
- do.entry="println \"do.entry running.rejected\""
- do.exit="println \"do.exit running.rejected\""
- },{
- name=delivering
- transition=[{
- guard=delivered
- to=delivered
- effect="println \"transition from running.delivering to running.delivered\""
- }]
- entry="println \"entry running.delivering\""
- exit="println \"exit running.delivering\""
- do.entry="println \"do.entry running.delivering\""
- do.exit="println \"do.exit running.delivering\""
- },{
- name=delivered
- transition=[{
- to=FINAL
- effect="println \"transition from running.delivered to FINAL\""
- }]
- entry="println \"entry running.delivered\""
- exit="println \"exit running.delivered\""
- do.entry="println \"do.entry running.delivered\""
- do.exit="println \"do.exit running.delivered\""
- }]
- transition=[{
- guard=cancel
- to=canceled
- effect="println \"transition from running to canceled\""
- },{
- guard=suspend
- to=suspended
- effect="println \"transition from running to suspended\""
- }]
- }]
イベント
以下の6つのイベントを定義しています。
- confirm
- 確認OK
- reject
- 確認却下
- delivered
- 配送済み
- cancel
- キャンセル
- suspend
- 保留
- resume
- 再開
前回からの変更点はありません。
エンティティ
エンティティの定義も前回から変更点はありません。
entity節の下にエンティティ「salesorder」を定義しています。
エンティティ「salesorder」の下にfeatures節で特性、attributes節で属性、statemachines節で状態機械を定義しています。
statemachines節の下に状態機械「status」を定義しています。
状態機械
定義したモデルの状態機械図は前回と同じ以下となります。
アクション
状態機械の以下の場所にアクションを定義しました。
- 状態のentry, exit, do.entry, do.exit
- 遷移のeffect
アクションはKaleidoxスクリプトでアクションの設定位置をコンソールに表示するものです。
実行
それでは実行してみましょう。
準備
まず、entity-create-collection関数を使ってエンティティを格納する入れ物であるコレクションの作成(内部的にはDBテーブルの作成)を行います。
- kaleidox> entity-create-collection 'salesorder
- true
この処理ではエンティティの状態遷移は起こらないのでコンソールへの表示は行われません。
エンティティの作成
次にentity-create関数でエンティティを作成します。
- kaleidox> entity-create 'salesorder price=100
- entry INIT
- do.entry INIT
- do.exit INIT
- exit INIT
- transition from INIT to running
- entry running.INIT
- do.entry running.INIT
- do.exit running.INIT
- exit running.INIT
- transition from running.INIT to running.applying
- entry running.applying
- do.entry running.applying
- do.exit running.applying
- exit running.applying
- transition from running.applying to running.confirming
- entry running.confirming
- do.entry running.confirming
- id:salesorder-67Yh9FdYry41hzuS9WDEtF;price:100;status:confirming
アクションの設定を行う前だと以下のようになっていたところですが、多数のアクションが実行されたことが分かります。この差分がアクションの動作ということになります。
- kaleidox> entity-create 'salesorder price=100
- id:salesorder-67Yh9FdYry41hzuS9WDEtF;price:100;status:confirming
それぞれ詳しく見ていきます。
オブジェクトが作成されると初期状態INITに入ります。初期状態INITへの進入時に呼ばれるentryアクションとdo.entryアクションが実行されました。
- entry INIT
- do.entry INIT
初期状態INITから最初の状態に自動的に移るので初期状態INITからの退出時に呼ばれるdo.exitアクションとexitアクションが実行されました。
- do.exit INIT
- exit INIT
次に初期状態INITから状態runningへの実際の遷移が行われます。
- transition from INIT to running
状態runningは状態の入れ子になっているので状態機械running内で新たな状態遷移が始まります。このため状態機械runningの初期状態に入り最初の状態applyingに遷移します。状態機械runningの初期状態INITへの進入処理としてentry, do.entry、退出処理としてdo.exit, exitアクションが実行され、初期状態INITから最初の状態applyingに遷移する中でeffectアクションが実行されます。
- entry running.INIT
- do.entry running.INIT
- do.exit running.INIT
- exit running.INIT
- transition from running.INIT to running.applying
状態applyingに入った後は自動的に状態confirmingに移ります。このため状態applyingへの進入処理、退出処理の各アクションが実行され、状態applyingから状態confirmingへの遷移アクションが実行されます。
- entry running.applying
- do.entry running.applying
- do.exit running.applying
- exit running.applying
- transition from running.applying to running.confirming
最後に状態confirmingへの進入時のアクションとしてentry, do.entryアクションが実行され状態confirmingに落ち着きました。
- entry running.confirming
- do.entry running.confirming
オブジェクトの状態を確認するとconfirmingとなっています。
- kaleidox> :show:pretty
- ┏━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
- ┃Name │Value ┃
- ┣━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
- ┃id │salesorder-67Yh9FdYry41hzuS9WDEtF┃
- ┃price │100 ┃
- ┃status│confirming ┃
- ┗━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
エベントの送出
event-call関数でCALLイベントconfirmをsalesorderエンティティ「67Yh9FdYry41hzuS9WDEtF」に対して送出します。
- kaleidox> event-call :entity 'salesorder 'confirm "67Yh9FdYry41hzuS9WDEtF"
- do.exit running.confirming
- exit running.confirming
- transition from running.confirming to running.confirmed
- entry running.confirmed
- do.entry running.confirmed
- do.exit running.confirmed
- exit running.confirmed
- transition from running.confirmed to running.delivering
- entry running.delivering
- do.entry running.delivering
- Event[confirm]
アクションの設定を行う前だと以下のようになっていたところです。この差分がアクションの動作ということになります。
- kaleidox> event-call :entity 'salesorder 'confirm "67Yh9FdYry41hzuS9WDEtF"
- Event[confirm]
それぞれ詳しく見ていきます。
まず状態confirmingから状態confirmedへの遷移が起こります。このため状態confirmingからの退出アクションdo.exit, exitが実行されます。続けて状態confirmingから状態confirmedへの遷移アクションが実行されます。
- do.exit running.confirming
- exit running.confirming
- transition from running.confirming to running.confirmed
状態confirmedから状態deliveringへの遷移は無条件なので自動で遷移が起こります。
状態confirmedへの進入アクションentry, do.entryに続いて退出アクションdo.exit, exitが実行されます。続いて状態confirmedから状態deliveringへの遷移アクションが実行されます。
- entry running.confirmed
- do.entry running.confirmed
- do.exit running.confirmed
- exit running.confirmed
- transition from running.confirmed to running.delivering
最後に状態deliveringへ進入するので状態deliveringのentry, do.entryアクションが実行されます。
- entry running.delivering
- do.entry running.delivering
ここで状態遷移は終わり状態deliveringに落ち着きました。
状態遷移の確認
confirmイベントを受信したsalesorderエンティティの状態をentity-get関数で確認します。
状態機械statusが状態confirmingから状態deliveringに遷移していることを確認できました。
- kaleidox> entity-get 'salesorder "67Yh9FdYry41hzuS9WDEtF"
- id:salesorder-67Yh9FdYry41hzuS9WDEtF;price:100;status:delivering
- kaleidox> :show:pretty
- ┏━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
- ┃Name │Value ┃
- ┣━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
- ┃id │salesorder-67Yh9FdYry41hzuS9WDEtF┃
- ┃price │100 ┃
- ┃status│delivering ┃
- ┗━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
まとめ
今回は状態機械のアクションの動作について確認しました。
状態遷移に伴って、設定したアクションが動作するのでイベント駆動の処理を自然に記述できます。
通常プログラミング言語で状態機械を実装するとそれなりのコード量になり、状態機械モデルとの関係も不明確になりがちですが、モデルそのものにアクションを設定することによりこのような問題が解消されます。
状態機械モデルを直接実行できることはモデル駆動開発の大きなアドバンテージになると思います。
諸元
- Kaleidox
- 0.3.4