Strutsフレームワーク
ようこそ
トップページ
キックスタートFAQ
ユーザガイド
リソース
私たちは誰でしょう
ダウンロード
バイナリ
ソースコード
はじめよう
インストール
リリースノート
APIドキュメント
メーリングリスト
バグ データベース
開発者ガイド
Beanタグ
HTMLタグ
Logicタグ
Templateタグ
Digester
Utilities
タグライブラリ ドキュメント
Beanタグ
HTMLタグ
Logicタグ
Templateタグ
現在の開発
インストール(ナイトリビルド)
リリースノート(ナイトリビルド)
APIドキュメント(ナイトリビルド)
ワークフローの提案
TODOリスト
背景と目標

Struts1.0は、モデル - ビュー - コントローラ タイプのデザインパターン(Front Controllerパターンとしても知られています)に基づいたWebアプリケーション構築プラットフォームとして、ますますポピュラーになっています。 ポピュラーになったのにはいろいろな理由がありますが、その中でも重要なことは以下のものです。

  • 基本的な構成原則の単純明快さ(一度理解してしまえばですが)
  • 片方の変更がもう一方に影響を与えないようにView層とModel層の分離を助ける論理的な名前づけの原則
  • JavaBeansによってModel層が公開する動的なコンテンツを含むページの作成を助ける豊富なツール群

しかし、元々のStrutsの設計の結果として、ユーザと2回以上のインタラクションが必要な(つまり2つ以上のJSPページおよび/あるいはアクションにわたる)ビジネストランザクションの構築には、あまり役に立たないフレームワークになってしまっています。各アプリケーションでナビゲーションを管理しないといけませんし、同様に論理コンテンツがページの境界をまたぐActionFormの処理もしなければなりません。

元々のStrutsの設計は、ページデザイナによる動的なページの作成に大いに役立っているだけでなく、ページデザイナがビジネスロジックをあまり気にしなくてよいようになっています(Model層とPresentation層の間の通信に使われるJavaBeansの名前以外は)。しかし、それでもなお、Struts1.0では、Actionクラスを作るために、Java開発者は(すべての機能ロジックがすでにJavaクラスの中で使えるとしても)ビジネスロジック側に関わる必要があります。

このワークフロー管理システムの提案の目的は、これらの設計の結果のいくつかに取り組むことです。特に以下の目標に取り組むことを意図しています。

  • 条件処理と分岐のサポートを含む、マルチユーザインタラクション(複数のユーザを介して行う)が必要なビジネスプロセスを構成できる(スクリプトで記述できる)手段を用意します。
  • ビジネスアプリケーションの専門家(必ずしもJava開発者ではない)が、任意のJavaクラスのpublicメソッドとして存在している既存のビジネス機能を統合できるようにするスクリプト要素をサポートします。
  • ページデザイナが、ワークフロー内もしくはワークフロー間でのナビゲーションリンクに対応するユーザインタフェース要素を作成するのを手助けします。
ユースケースとサンプル

ここでスクリプトで記述されたワークフローアクティビティがどんな感じになりそうか、ここでその雰囲気を紹介することは、ユースケースシナリオを考えるのに役立つでしょう。 ただし、サンプルとして示した文法は、どんなことが可能かを説明するためのものであり、こうしなければならない、というものではありません。厳密に作ろうとしたものではなく、これらのサンプルの間での一貫性は(もしくはこれらのサンプルの内部での一貫性さえも)保証されていません。

アプリケーションログオン

(他の多くのWebアプリケーションのように)Strutsに含まれているサンプルアプリケーションでは、ログオンフォームを含む、アプリケーションによって管理されるセキュリティを使っています。 ユーザ名とパスワードでユーザの認証を行えるビジネスロジックBeanが、(どこかのスコープのキーauthenticatorの下で)利用可能であると想定してみてください。その場合、ログオンアプリケーションのスクリプト記述を以下のように行うことができます。

<activity id="Application Logon">

  <-- ログオンフォームの表示(Webフレームワーク非依存) -->
  <web:forward id="display" page="/logon.jsp"/>

  <-- ユーザ名とパスワードの認証。もし認証されれば本人属性が、
      だめならNullが返される -->
  <web:set  name="username" value="$parameter:username"/>
  <web:set  name="password" value="$parameter:password"/>
  <core:invoke bean="authenticator" method="authenticate">
    <core:param type="java.lang.String" value="$username"/>
    <core:param type="java.lang.String" value="$password"/>
    <core:return name="principal"/>
  </core:invoke>

  <-- もし本人属性が返されなければログオンフォームに戻るように分岐する -->
  <core:if expr="$principal == null">
    <web:set name="error" value="$messages.lookup('invalid.logon')"/>
    <core:branch idref="display"/>
  </core:if>

  <-- 終了して「メインメニュー」ワークフローに戻る -->
  <core:goto name="Main Menu"/>

</activity>
単純な複数ページのウィザード

複雑なデータ入力操作の多くは、最終的にはリクエストの処理に必要な情報すべてが得られるように、いくつか(しばしば1つ)の質問をたずねる一連の単純なダイアログページに分割することで、(ユーザの視点から)単純にすることができます。多くの場合、インタラクションのページごとにナビゲーションコントロールを持ち、ユーザは残りの質問に答えずにすぐに実行したり、インタラクション全体を取り消すことができます。そのようなインタラクションは、以下のようにモデル化することができます。

<activity id="Simple Wizard Application">

  <!-- インタラクションの1ページ目を表示 -->
  <!-- (Struts固有の論理・物理マッピングを使用) -->
  <struts:forward id="page1" name="Simple Wizard Page 1">

  <!-- 1ページ目でのナビゲーション入力の処理 -->
  <!-- (このようにフレームワーク非依存にもすることができます) -->
  <struts:navigate>
    <struts:branch control="CANCEL" idref="cancel"/>
    <struts:branch control="FINISH" idref="finish"/>
    <struts:branch control="NEXT"   idref="page2"/>
  </struts:navigate>

  <!-- インタラクションの2ページ目を表示 -->
  <struts:forward id="page2" name="Simple Wizard Page 2">

  <!-- 2ページ目でのナビゲーション入力の処理 -->
  <struts:navigate>
    <struts:branch control="CANCEL" idref="cancel"/>
    <struts:branch control="FINISH" idref="finish"/>
    <struts:branch control="NEXT"   idref="page3"/>
    <struts:branch control="PREV"   idref="page1"/>
  </struts:navigate>

  <!-- インタラクションの3ページ目を表示 -->
  <struts:forward id="page3" name="Simple Wizard Page 3">

  <!-- 1ページ目でのナビゲーション入力の処理  -->
  <struts:navigate>
    <struts:branch control="CANCEL" idref="cancel"/>
    <struts:branch control="FINISH" idref="finish"/>
    <struts:branch control="PREV"   idref="page2"/>
  </struts:navigate>

  <!-- 適宜、FINISHナビゲーションコントロールを処理する -->
  <xxx:yyy id="finish" .../>
  <core:goto name="Main Menu"/>

  <!-- 適宜、CANCELナビゲーションコントロールを処理する -->
  <xxx:yyy id="cancel" .../>
  <core:goto name="Main Menu"/>

</activity>

この例にはありませんが、あるページでの選択がフロー全体のうちのいくつかのページをスキップするかどうかに影響するような状況を調べてみるのも興味深いでしょう。

ユーザに見える特徴

ワークフローシステムの各機能はJava APIを通じてアプリケーションに公開されます。これらのAPIはあるアクティビティの静的な記述と、動的な処理状態の両方を示します。 システムの汎用性および柔軟性を最大限にするために、適切な場所でオブジェクトファクトリとプラグイン可能な実装パターンが使用されなければなりません。

ワークフロー管理システムの実装オブジェクト

以下のクラスが、ワークフロー管理システムの主なコンポーネントです。

レジストリ - 複数のプロセスおよびアクティビティの静的な記述を格納するコレクション。String型のキーを使って格納・取り出しが可能です。

プロセス - ツリー状になったビジネスアクティビティの静的な記述。しばしば別々の個人(もしくはアプリケーションシステム)によって、ネストした形で実行されます。

アクティビティ - 連続したステップの静的な記述。一般に単独の個人(もしくはアプリケーションシステム)によって、適度に短い時間内に実行されます。

ステップ - 個々のタスクの静的な記述。独立し、分割不可能な最小単位として実行されます。ステップは、ループや条件処理で使えるように、他のステップ内でネストすることもできます。(任意のJavaオブジェクトの任意のメソッドの実行といったパワフルな機能を含む)豊富なビルトイン・ステップが提供されなければなりませんし、一連のサポートされたステップの実装を拡張するメカニズムによって、自由に拡張が可能になります。

コンテキスト - アクティビティ(あるいはネストした1組のアクティビティ)全体としての動的な処理状態。他のステップで作成されたJavaBeansや他のステップで利用するJavaBeansのための記憶領域の準備を含みます。ステップの実行はコンテキストに記録されるので、アクティビティの処理を中断したり後で再開することができます。

スコープ - String型のキーによって任意のJavaオブジェクトの格納・取り出しができるMapです。 コンテキストは多くの個別のスコープをサポートします。各スコープはアプリケーションロジックからプラグイン可能であり、既存のアプリケーションの機能に統合できます。例えば、Webアプリケーションの実装において、スコープは一般に、Servlet APIによって提供されるような、リクエスト属性、セッション属性、サーブレットコンテキスト属性に直接マッピングされるでしょう。

ビルトインステップ

豊富なビルトインステップの実装(および指定したネームスペースに対応するXML要素)が、基本ワークフローエンジンの一部として、そして関連するStrutsへのこのエンジンの統合の一部として提供されます。

Beanインタラクション - (オブジェクトの実際のコレクションにコンテキスト経由でマッピングされた)任意のスコープ内でJavaBeansを取得および設定する能力。

制御フロー - 条件分岐およびループ。制御フローのステップは任意の深さまでネストした一連のステップを含みます。

メソッド実行 - あるスコープに格納されたBeanの任意のパブリックメソッドの実行。その際、指定した引数(表現もしくはBeanの参照)を渡し、(もしあれば)メソッドの結果をあるスコープ内のBeanに返します。アプリケーションを作成する際にワークフローシステムの有用性が最大限になるよう、これらのステップが相互作用することができるオブジェクト・タイプに制限を加えてはいけません

アクティビティ管理 - (現在のアクティビティを終了して)指定したアクティビティにGOTOし、指定したアクティビティをCALLし(呼びだしたアクティビティから戻ると現在のアクティビティが再開します)、呼びだしたアクティビティからRETURNし、アクティビティシステムからEXITします。

ユーザー・インタラクション - アプリケーションの指定する方法でユーザと対話するためにワークフロー実行を中断すること。例えば、Webアプリケーションがページを表示し、ワークフローを再開するまで入力のサブミットを待つ場合です。

特殊プロセス - 共通プロセス機能のためにあらかじめ構築されたステップ。XSLT変換や任意のSQLクエリーの実行、メール送信などがあります。

実装に関するメモ

この提案の実装は、3つの主な開発の層に分割されます:

  • コアのワークフロー管理システム機能とアプリケーション環境に依存しないビルトインステップの実装 [jakarta-commonsのコード]
  • どの特定のアプリケーションフレームワークにも依存しないやり方でServletAPIと統合されるワークフロー管理システムコンポーネントの特殊な実装 [jakarta-commonsのコード]
  • Strutsの内部アーキテクチャーおよびカスタムタグライブラリと緊密に統合されるワークフロー管理システムコンポーネントの特殊な実装 [jakarta-strutsのコード]

ワークフロー管理システムは、Beanの隠蔽を実現するスコープという一般的な概念を、異なる動作環境に統合するためのプラグイン可能な実装とともにサポートするでしょう。 ワークフローエンジン自身のAPIは全て、Web層を参照しません(つまり、javax.servlet.* をインポートしません)。

適切なオブジェクトファクトリーとプラグインを可能にするAPIは、基本フレームワークの拡張性を保証します。

ビジネストランザクションのスクリプトは、適切なDTDおよび/あるいはスキーマに準拠したXML文書の中でコード化されるでしょう。 使用されるXML技術は、ステップなどのコンポーネントのXML記述、およびそれらを実装する一連のJavaオブジェクトの両方において、ステップなどのコンポーネントの拡張可能な定義を容易にするでしょう。

ステップのXML表現の文法の詳細を設計する際には、高度な開発ツールが全体のパフォーマンスを最適化するためにアクティビティを個々のクラスに「コンパイルする」のが妥当かどうかを検討しなければなりません。

ステップのXML表現の文法の詳細を設計する際には、 ビジネストランザクションのスクリプト化という考え方と多少なりとも似ている他のXMLアプリケーションの文法をまねることを検討すべきでしょう。 考慮すべきモデルをいくつか挙げます。

  • XSL Transformations(XSLT) - 広く認知・理解されつつある制御フローのメカニズムを含んでおり、それらをまねることができるでしょう。
  • JSP Standard Tag Library (Early Access) - (Javaコミュニティー・プロセスの下でJSR-052のエキスパートのグループによって作られた)このライブラリの多くのJSPカスタム・タグの設計目標は、 条件分岐、ループ、任意のスコープのオブジェクトとの相互作用に関する有用なモデルを十分に得られるほど類似しています。 (訳注:バージョンは原文作成当時のものです。)

ビルトイン・アクションの有用性を最大限にするために、 現在のコンテキストに結びついているスコープにあるオブジェクトを操作することができる表現言語がサポートされる必要があります。 考慮すべきモデルをいくつか挙げます。

  • XML Path Language (XPath) - XML仕様書の至る所で使用されているので、XML指向アプリケーションの開発者が習熟しています。
  • JavaScriptのような表現言語 - ページ開発者が習熟しています(Struts開発者が、ネストしていたり索引がついた多くのStrutsタグのプロパティアクセサ文法に習熟しているのと同様です)。

ワークフロースクリプト開発者の視点から見て、XMLネームスペースはステップの実装を拡張するのに使用されるでしょう。特定のネームスペースを、(そのネームスペース内の)1組の正しいXML要素や、対応するJavaクラス(それらのステップの機能を提供します)にマッピングするメカニズムが必要です。

Web層統合には、(ワークフローの観点から見た)スコープを、Web層の標準のリクエストセッションアプリケーションスコープにマッピングするためのメカニズムが含まれます。 したがって、ワークフロー・スクリプトは、適切な(JSPページがデータをプレゼンテーションへ直接引っ張ってこれるような)スコープに、Beanを配置することが可能でなければなりません。 それは、Strutsアクション(とそれらのアクションから呼ばれるビジネスロジッククラス)が、Struts1.0ベースのアプリケーションに、Beanを配置することが可能であるのに似ています。 これらの機能を利用することで、アプリケーション開発者は、Javaプログラマを巻き込んで新しいアクションを作成してもらう(あるいは構成する各部分からビジネスロジックを合成してもらう)必要なしに、ビジネスロジックBeanのメソッドとしてすでに利用可能な機能ロジックを結合することで、多くのアプリケーションのビジネスロジック要件を「スクリプトにする」ことができるでしょう。

Web層統合のコンポーネントは、ServletおよびJSPの仕様にあるAPIをインポートしてもかまいませんが、アプリケーション固有のフレームワークのAPIはインポートしてはいけません。フレームワーク固有の統合は、汎用的なWeb層統合の上で行われるでしょう。

さらに、String型開発者がナビゲーションのリンクやコントロールを作成しやすいように、Struts統合には小規模なカスタムタグライブラリが含まれます。 コントロールの例として、 ウィザードダイアログページの「次へ」「前へ」「完了」のリンク、ワークフローを途中で終了するための「キャンセル」ボタン、もしくはサブルーチンとして新規ワークフローを起動し、元のワークフローの現在のステップに戻ってくる「起動」ボタンなどがあります。 これらの機能を利用することで、ページ開発者は、ナビゲーションの複雑なところを気にしないで、ワークフローダイアログの個々のビジュアルな部分を作成することができます。


Copyright (c) 2000-2002, Apache Software Foundation

[訳注: これは内田由紀、高橋達男が翻訳しました。日本語訳に対するコメントがあれば、report@jajakarta.orgに送って下さい。]