第9章 ページフローとビジネスプロセス
JBoss jBPM は Java SE や EE 環境向けのビジネスプロセス管理エンジンです。 jBPM はビジネスプロセスやユーザーインタラクションを待ち状態やデシジョン、 タスク、 Web ページなどを表すノードのグラフとして表現します。 グラフは jPDL と呼ばれるシンプルで非常に読みやすい XML 言語で定義され、 Eclipse プラグインを利用してグラフィカルに編集や表示を行うことができます。 jPDL は拡張可能な言語であり、 WEB アプリケーションのページフローの定義から典型的なワークフローの管理、 また SOA 環境におけるサービスのオーケストレーションまで幅広く対応します。
Seam アプリケーションは、複雑なユーザーインタラクションでページフローの定義を行う、 また包括的なビジネスプロセスの定義を行うという 2 種類の異なる問題に jBPM を使用します。
前者の場合、 jPDL プロセス定義は単一の対話に対してページフローを定義するのに対し、Seam の対話は 1 ユーザーとの比較的実行期間が短いインタラクションであると考えられます。
後者の場合、 ビジネスプロセスは複数ユーザーの複数の対話にまたがることがあります。 その状態は jBPM データベースでは永続であるため、長期実行とみなされます。 複数ユーザーのアクティビティの調整は、 単一ユーザーとのインタラクションについて動作を記述するより複雑となるため、 jBPM は複数の並列実行パスやタスクを管理するための高度な機能を提供します。
注記
ページフローと包括的なビジネスプロセスは混同しないようにしてください。 異なる粒度レベルで動作します。 ページフロー、 対話、 タスクはすべて単一ユーザーとの単一の操作となります。 ビジネスプロセスは多くのタスクにまたがります。 また、 この 2 つの jBPM アプリケーションは互いに依存性がないので、 一緒に使用することも別々に使用することもでき、 まったく使用しなくても構いません。
注記
Seam を使用する上で jPDL の知識は必要ありません。 JSF や Seam ナビゲーションルールでページフローを定義し、 アプリケーションがプロセス駆動というよりデータ駆動となる場合は恐らく jBPM は必要ありません。 ただし、 明確に定義されたグラフィカルな表現という観点からユーザーによる操作を考えるとより堅牢なアプリケーションの構築に役立ちます。
9.1. Seam のページフロー リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Seam にはページフローを定義する 2 つの方法があります。
- JSF あるいは Seam ナビゲーションルールを使用します - ステートレスなナビゲーションモデル
- jPDL を使用します - ステートフルなナビゲーションモデル
簡単なアプリケーションではステートレスなナビゲーションモデルで十分です。 複雑なアプリケーションになる場合は両方を組み合わせて使用します。 各モデルはそれぞれに長所と短所があるのでそれらを考慮に入れ実装を行ってください。
9.1.1. 2 種類のナビゲーションモデル リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
ステートレスなモデルは一組の名前の付いた論理的なイベントの結果から直接、結果として生じるビューページへのマッピングを定義します。 ナビゲーションルールはイベントの発生源となるページ以外、 アプリケーションで保持される状態はすべて無視します。 したがって、 アクションリスナーのメソッドしかアプリケーションの現在の状態にアクセスできないため、 このアクションリスナーのメソッドがページフローに関する決定を行わなければならない場合があります。
これは JSF ナビゲーションルールを使用したページフロー定義の例です。
これは Seam ナビゲーションルールを使用した同じページフロー定義の例です。
ナビゲーションルールが冗長過ぎると感じる場合は、 アクションリスナーのメソッドから直接ビュー ID を返すことができます。
これはリダイレクトとなるので注意してください。 リダイレクトで使用するパラメータを指定することもできます。
public String search() {
return "/searchResults.jsp?searchPattern=#{searchAction.searchPattern}";
}
public String search() {
return "/searchResults.jsp?searchPattern=#{searchAction.searchPattern}";
}
ステートフルなモデルは名前の付いた論理的なアプリケーションの状態間で起こる遷移の一式を定義します。 このモデルでは jPDL ページフロー定義中にあらゆるユーザー操作のフロー表現が可能となるため、 インタラクションのフローを全く認識しないアクションリスナーのメソッドを記述することができます。
これは jPDL を使用したページフロー定義の例です。
ここで、 すぐ気付くことが 2 つあります。
- JSF と Seam ナビゲーションルールは非常にシンプルです。 (しかし、 根底となる Java コードはより複雑であるという事実を隠しています。)
- jPDL によりユーザー操作がとたんに理解しやすくなるため、 JSP や Java コードを見る必要性がなくなります。
また、 ステートフルモデルはさらに制約的です。 それぞれの論理的な状態 (ページフローの各ステップ) に対して他の状態に遷移可能な制約された一式があります。 ステートレスモデルは アドホックな モデルとなるため、 アプリケーションではなくユーザーが次に行きたいところを決めるような比較的制約のない自由な操作に適しています。
ステートフルとステートレスのナビゲーションの違いは、 モーダルのビューと非モーダルのビューによく似ています。 Seam のアプリケーションは単純な意味では通常はモーダルではありません。 実際、 モーダルな動作を回避するために対話を使用します。 ただし、 Seam アプリケーションは任意の対話のレベルではモーダルとなる場合があり、 また頻繁にモーダルとなります。 ユーザーが行う操作の順番を予測することは非常に困難であるためモーダルな動作は避けるのが最適ですが、 ステートフルモデルでは存在意義があります。
2 つのモデルの最大の違いは戻るボタンの動作です。
9.1.2. Seam と戻るボタン リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
JSF あるいは Seam ナビゲーションルールが使用される場合、 ユーザーは戻るボタン、 進むボタン、 更新ボタンを使って自由な操作を行うことができます。 内部的な対話状態の一貫性を保持するのがアプリケーションの役割です。 開発者は Web アプリケーションのフレームワークやステートレスなコンポーネントのモデルを扱う経験を通してこれがいかに困難であるかを学んできました。 ステートフルなセッション Bean で支えられる明確に定義された対話モデルとなるような Seam ではこれが非常に簡単になります。 通常、 アクションリスナーのメソッドの冒頭で
no-conversation-view-id を null チェックと組合わせるだけです。 大抵望まれるものは自由なナビゲーションへの対応となります。
この場合、
no-conversation-view-id の宣言は pages.xml で行います。 現在は存在していない対話で表示されたページからの要求の場合には別のページにリダイレクトを行うよう指示します。
<page view-id="/checkout.xhtml" no-conversation-view-id="/main.xhtml"/>
<page view-id="/checkout.xhtml" no-conversation-view-id="/main.xhtml"/>
一方、 ステートフルモデルでは戻るボタンを押すと前の状態に戻る未定義の遷移と解釈されます。 ステートフルモデルは現在の状態から定義された遷移セットを強制実行するため、 戻るボタンはステートフルモデルではデフォルトで許可されません。 Seam は透過的に戻るボタンの使用を検出して前の「古い」ページのアクション試行をブロックして、 ユーザーを「現在の」ページにリダイレクトします (そして Faces メッセージを表示)。開発者にとってはこれはステートフルモデルの特長になりますが、 ユーザーにとってはイライラさせられることがあります。
back="enabled" を設定すると特定のページノードからの戻るボタン操作を許可することができます。
これは、
checkout 状態から以前のどの状態にでも戻るボタンでの移動が可能です。
注記
遷移の後にリダイレクトを行うようページ設定されている場合、 流れの後半のページで戻るを有効にしていても戻るボタンでユーザーがそのページに戻ることはできません。 Seam はページスコープにページフローに関する情報を格納し、戻るボタンは復元されるその情報の POST にならなければならないためです (Faces 要求を通じてなど)。 リダイレクトはこのリンクを提供します。
ページフローの間にレンダリングされたページから要求が発生し、 そのページフローを持つ対話がすでに存在していない場合は、何が起こるかを定義しなければなりません。この場合
no-conversation-view-id 宣言はページフロー定義で行います。
実際にはいずれのナビゲーションモデルとも使い道があります。 どんなときにどちらのモデルの方が適切かを理解するために、これから簡単に学んでいきます。