ウィザード処理
目的
1 つまたは複数のオブジェクトに関する情報をユーザーから収集するための JSP ウィザードを作成しました。次は、この情報を処理し、オブジェクトに対してデータベース操作を実行するためのコードを作成する必要があります。
バックグラウンド
いずれかの組み込みボタンセットをウィザードで使用する場合、ユーザーが「完了」、「適用」、「保存」、または「チェックイン」のいずれかのボタンをクリックしてフォームを送信すると、ActionControllerの processRequest() メソッドを起動する JavaScript 関数が呼び出されます。WizardServlet は、HTTP フォームデータやほかのウィザードコンテキスト情報 (ウィザードが起動された場所など) を NmCommandBean に読み込みます。次に、WizardServlet は NmCommandBean を FormDispatcher クラスに渡します。FormDispatcher は FormProcessorController を呼び出します。
FormProcessorController はフォームデータを ObjectBeans に分割します。ウィザードのターゲットオブジェクトごとに 1 つの ObjectBean が作成されます。この ObjectBean には、そのオブジェクト別のすべてのフォームデータと、全オブジェクトに共通するフォームデータが含まれています。FormProcessorController は ObjectFormProcessors というクラスに ObjectBeans を渡します。このクラスはウィザードに適したタスク (データベースへの新規オブジェクトの作成、データベース内のオブジェクトの更新、オブジェクト ObjectFormProcessors のチェックインなど) を実行し、ObjectFormProcessorDelegates というクラスを呼び出して 1 つ以上のサブタスクを実行できます。
ウィザードが 1 つのオブジェクトに対して操作を実行する場合、ウィザード別にタスクを実行する独自の ObjectFormProcessor または ObjectFormProcessorDelegates を作成しなければならない場合があります。ただし、ウィザードでオブジェクトを作成または編集する場合は、製品に同梱されている、オブジェクトの作成および編集用のプロセッサを利用しても構いません。
ウィザードに複数のターゲットオブジェクトが含まれている場合は、オブジェクトが処理される順序を制御する独自の FormProcessorController を作成しなければならない場合があります。ただし、作成する必要がない場合もあります。
範囲/適用可能性/前提条件
必要な JSP、データユーティリティ、GUI コンポーネント、およびウィザードを表示するレンダラーがすでに作成されていることを前提とします。また、ウィザードを UI に接続するために必要な操作も作成されていることを前提とします。
予測される結果
1 つまたは複数の Windchill オブジェクトに関連するデータベース操作を実行します。
ソリューション
JSP クライアントアーキテクチャフレームワークと共通のコンポーネントを使用して、ウィザードフォームデータを処理し、1 つまたは複数のオブジェクトに該当するデータベースタスクを実行します。
前提となる知識
この目的を達成するには、次のことを理解している必要があります。
• Java プログラミング
• HTML フォームを使用した基本的な Web 開発
• ウィザードについて適切なタスクを実行するために必要な Windchill サービス API やその他の API の知識
このセクションで使用する用語の定義
用語
|
定義
|
ターゲットオブジェクト
|
ウィザードでデータの収集対象となるオブジェクト。ウィザード処理において、一部の操作は通常、ターゲットオブジェクトに対して実行されます。
|
ソリューションエレメント
エレメント
|
タイプ
|
説明
|
ActionController
|
Java クラス
|
このクラスにはウィザードフォームデータが投稿されます。このクラスは、処理完了後にブラウザに返されるレスポンスページを送信します。
ランタイム場所: <Windchill>/srclib/CommonComponents-web.jar
|
FormProcessorController
|
Java インタフェース
|
このインタフェースを実装するクラスは、ウィザードタスクを実行するために ObjectFormProcessor をインスタンス化して呼び出します。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
DefaultFormProcessorController
|
Java クラス
|
FormProcessorController のデフォルト実装。すべてのシングルオブジェクトウィザードについてはこれで十分です。このコントローラは、HTML フォームデータを ObjectBean に分割し、これらの ObjectBean を ObjectFormProcessors に渡します。
マルチターゲットオブジェクトウィザードでは、オブジェクトの処理順を制御するためにこのクラスを拡張しなければならない場合があります。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
ObjectFormProcessor
|
Java インタフェース
|
このインタフェースを実装するクラスは、フォームデータを使用して、ウィザードに該当するデータベースタスクと関連タスクを実行します。各ウィザードには ObjectFormProcessor クラスが 1 つだけ配置されますが、マルチオブジェクトウィザードの場合は、このクラスのインスタンスを複数含めることができます。
ObjectFormProcessor は、ObjectFormProcessorDelegate を呼び出してサブタスクを実行することができます。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
DefaultObjectFormProcessor
|
Java クラス
|
ObjectFormProcessorDelegate やその他のいくつかの共通タスクを実行するためのロジックが含まれている ObjectFormProcessor のデフォルト実装。ウィザード固有のプロセッサによって拡張しなければならない基本クラスです。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
ObjectFormProcessrDelegate
|
Java インタフェース
|
このインタフェースを実装するクラスは、処理サブタスクを実行するために ObjectFormProcessor によって呼び出されます。複数のウィザードに共通するタスクを処理するために、複数の ObjectFormProcessorDelegate を 1 つのプロセッサによって呼び出して同じ委任を複数のプロセッサで使用することができます。これらはオプションです。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
DefaultObjectFormProcessorDelegate
|
Java クラス
|
ObjectFormProcessorDelegate のデフォルト実装。このクラスは、サブクラスが実装する必要のないメソッドについて no-op (動作なし) を提供します。タスク固有の委任によって拡張しなければならない基本クラスです。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
ObjectBean
|
Java クラス
|
特定のターゲットオブジェクトに固有のフォームデータと、すべてのオブジェクトに共通するデータのコンテナ。所定のオブジェクトのフォームデータを取得するメソッドを提供します。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
ProcessorBean
|
Java クラス
|
どの ObjectBean を同じプロセッサインスタンスが処理するか、およびその処理順を認識している、ObjectBean のコンテナ。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
FormResult
|
Java クラス
|
サーバーメソッド間、およびサーバーと WizardServet 間でメソッド結果を受け渡すために使用されるクラスです。
ランタイム場所: <Windchill>/srclib/CommonComponents.jar
|
ウィザード処理フレームワークにおける主要な Java クラス間の関係を、以下の UML 図に示します。
フォーム処理のタスクフロー
フォームデータを処理する際、ウィザードターゲットオブジェクトに対して複数のタスクが実行される場合がよくあります。これらは基本的に、以下のシーケンスに従って実行されます。
1. 前処理
この段階では、データベース操作のセットアップが行われます。以下に例を示します。
◦ オブジェクト作成ウィザードの場合、フォームデータの値からオブジェクトのインスタンスが作成され、オブジェクトの属性が設定されます。
◦ オブジェクト編集ウィザードの場合、フォームデータの値に基づいてオブジェクトがデータベースから取得され、オブジェクトの属性が修正されます。
2. データベーストランザクションブロックの開始
3. データベース操作の実行。以下に例を示します。
◦ オブジェクト作成ウィザードの場合、オブジェクトはデータベースに保存されます。
◦ オブジェクト編集ウィザードの場合、オブジェクトはデータベース内で更新されます。
4. 後処理
主要なデータベース操作を終了した後、同じトランザクションブロックを開始する前に実行しなければならないデータベースタスクやその他のタスクを行い、これらのタスクが失敗した場合にデータベース操作がロールバックされるようにします。通常、以下のタスクでは、ターゲットオブジェクトを事前に永続化しておく必要があります。以下に例を示します。
◦ オブジェクトを別のコンテナと共有する
◦ オブジェクトをワークフローに送信する
5. データベーストランザクションブロックの終了
6. トランザクションの後処理
タスク失敗時にデータベーストランザクション全体がロールバックされないように、トランザクションブロックを終了した後に実行しなければならないタスクを行います。以下に例を示します。
◦ オブジェクトのチェックアウト
必要に応じ、この段階で追加のデータベース操作を実行できます。
各処理段階のタスクは、ObjectFormProcessors および ObjectFormProcessorDelegates によって実行されます。ウィザードには、DefaultObjectFormProcessor を拡張する ObjectFormProcessor が必要です。これがウィザードに適したタスクを制御し処理するためのプライマリクラスとなります。
ウィザードには、1 つまたは複数の ObjectFormProcessorDelegates を任意で持ちます。これは、ObjectFormProcessor によって (DefaultObjectFormProcessor を経由して) 呼び出され、サブタスクの処理を実行します。ObjectFormProcessorDelegates では、DefaultObjectFormProcessorDelegate クラスを拡張してください。ObjectFormProcessorDelegates の詳細については、ウィザードに必要な ObjectFormProcessorDelegate クラスの作成を参照してください。
ObjectFormProcessor クラスと ObjectFormProcessorDelegate クラスには、各処理フェーズの中でタスクを実行するための preProcess()、doOperation()、postProcess()、および postTransactionProcess() メソッドがあります。
| ユーザーがウィザードのステップを進めると、ウィザードステップバリデータが呼び出されます。検証を実行する必要があるオブジェクトを準備するため、ObjectFormProcessor および ObjectFormProcessorDelegate クラスの preprocess() メソッドが実行されます。 |
すべてのウィザードにすべてのフェーズのタスクが配置されるわけではありません。したがって、デフォルトクラスである DefaultObjectFormProcessor および DefaultObjectFormProcessorDelegate からこれらのメソッドを拡張する場合、すべてのプロセッサおよび委任にこれらの全メソッドを実装する必要はありません。親クラスがデフォルトで各メソッドを実装します。ObjectFormProcessor にこれらのいずれかのメソッドを実装する場合、ObjectFormProcessorDelegates の呼び出しを処理する、DefaultObjectFormProcessor の super() メソッドが呼び出されます。
HTML フォームデータは、ObjectBeans のリストとして ObjectFormProcessors と ObjectFormProcessorDelegates に渡されます。ObjectBean には、1 つのターゲットオブジェクトに固有のデータと、すべてのターゲットオブジェクトに共通のデータが格納されています。1 つのターゲットオブジェクトが含まれたウィザードの場合、このリストには 1 つの ObjectBean だけが格納されます。複数のターゲットオブジェクトが含まれたウィザードの場合、このリストには、ターゲットオブジェクトごとに 1 つの ObjectBean が含まれています。これらの ObjectBeans は、オブジェクト間の関係とそれらの処理の順序を表すツリー構造に編成できます。ObjectBeans の作成は、FormProcessorController によって処理されます。
また FormProcessorController は、データトランザクションの開始/終了やロールバック (必要に応じて)、および ObjectFormProcessors の呼び出しも処理します。後者について、DefaultFormProcessorController は、ProcessorBeans というオブジェクトを使用します。親オブジェクト、タイプ、ObjectFormProcessorDelegates が同じであるターゲットオブジェクトは同じ ProcessorBean に配置されます。
各 ProcessorBean には、その中の ObjectBeans に ObjectFormProcessor と ObjectFormProcessorDelegates の独自のインスタンスが格納されます。ProcessorBeans は、オブジェクトの処理順序を制御するツリー構造に編成することができます (1 つのターゲットオブジェクトが含まれたウィザードには 1 つの ProcessorBean しか配置されません)。
DefaultFormProcessorController のタスクフローは以下のとおりです。
1. ルート ProcessorBean について ObjectFormProcessor の preProcess() メソッドを呼び出し、ProcessorBean を使用してこのメソッドに ObjectBeans を渡します。さらに、ルート ProcessorBean の子について、子リストに現れる順序でこのプロセッサの preProcess() メソッドを呼び出します。次に、子の子について preProcess() メソッドを呼び出します。
2. Transaction.start() を実行します。
3. ルート ProcessorBean とその子について、preProcess() と同じ方法で ObjectFormProcessor の doOperation() メソッドを呼び出します。
4. ルート ProcessorBean とその子について、preProcess() と同じ方法で ObjectFormProcessor の postProcess() メソッドを呼び出します。
5. ステップ 1 ~ 4 が成功した場合は、Transaction.commit() を実行します。
6. ルート ProcessorBean とその子について、preProcess() と同じ方法で ObjectFormProcessor の postTransactionProcess() メソッドを呼び出します。
あるメソッドによって FormProcessingStatus.FAILURE というステータスが返された場合、コントローラは、HTML レスポンスページに必要な情報を設定できるように、失敗した ObjectFormProcessor の setResultNextAction() メソッドを呼び出します。
| トランザクションのネスティングは推奨されていないので、ステップ 3 またはステップ 4 で追加トランザクションブロックを ObjectFormProcessors で開いてコミットすることはしないでください。 |
複数のターゲットオブジェクトが含まれたウィザード
サポートされているマルチオブジェクトウィザードのタイプは以下の 2 つです。
• 関連のないターゲットオブジェクトが複数含まれたウィザード
例: 複数部品の作成
• 関連するターゲットオブジェクトのツリーが含まれたウィザード
例: 変更通知とこれに関連する変更タスクの作成
オブジェクトに固有のデータは、そのオブジェクトのテーブル行か、そのオブジェクトのウィザードステップに含めてください。各行が作成される部品を表し、各列が部品の属性を表している表の例を以下に示します。
各ウィザードステップでは、以下のいずれかのデータタイプを表示する必要があります。
• 各行が異なるオブジェクトを表している表形式のデータ
• 作成されたオブジェクトのいずれか 1 つのみに固有のデータ
• 作成されたすべてのオブジェクトに共通のデータ
表形式でないかぎり、複数のオブジェクトについてオブジェクト固有のデータをステップに含めることはできません。
マルチオブジェクトウィザードでは、入力フィールドが適用されるオブジェクトは、HTML input フィールドの name 属性に埋め込まれた "objectHandle" によって識別されます。例:
<input id="null1188140328133"
name="<someFieldIdString>!~objectHandle~newRowObj_430512131997223~!
<someAdditionalText>" value="" size="60" maxlength="60"
type="text">
上記の例の "newRowObj_430512131997223" はオブジェクトハンドル、"!~objectHandle~" は必須プリフィックス、"~!" は必須サフィックスです。オブジェクトハンドルが埋め込まれた HTML 名属性には任意の文字列を使用できます。オブジェクトハンドルは、文字列内のどの位置に配置しても構いません。
DefaultFormProcessorController は、フォームデータを ObjectBeans に読み込むと、必須プリフィックスおよびサフィックスを含むオブジェクトハンドルを名前属性から取り外し、その結果生成された文字列を、フォームデータパラメータマップの値のキーとして使用します。たとえば、上記の入力フィールドのフォーム値を取得するには、次のキーを使用して ObjectBean.getTextParameter() を呼び出します。
<someFieldIdString><someAdditionalText>
フレームワークは、以下のいずれかの方法に従って、name 属性内のオブジェクトハンドルを生成します。
• オブジェクトのデータが表形式 (各行がオブジェクトを表し、各列がオブジェクトの属性を表す) で捕捉された場合、次のようにビルダーでテーブルコンフィギュレーションに rowBasedObjectHandle=true を設定すると、オブジェクトハンドルは動的に生成されます。
table.setRowBasedObjectHandle(true);
各行のオブジェクトハンドルはその行の OID に基づきます。
objectHandle = CreateAndEditWizBean.getNewObjectHandle(next.getOid().toString());
• あるウィザードステップのすべてのデータが同じオブジェクトに関するものである場合は、ウィザードステップ操作について、そのオブジェクトのオブジェクトハンドルを指定します。
<jca:wizardStep action="setContextWizStep" type="object"
objectHandle="<your object handle string>" …
ウィザードステップのデータが、作成されたすべてのオブジェクトに共通するものである場合は、入力フィールドについてオブジェクトハンドルを指定する必要はありません。ObjectBean 内のデータに関連付けられているオブジェクトハンドルには、ObjectBean.getObjectHandle() メソッドによってアクセスできます。FormProcessorController は、以下のセクションで説明するように、ObjectBeans を処理するためにプロセッサが呼び出される順序を制御します。以下の図では、ObjectBeans が円で表されています。同じタイプのオブジェクトを表す円には、同じシェードを付けています。
関連のない複数のターゲットオブジェクト
通常、複数の関連のないターゲットオブジェクトをウィザードに含める場合、オブジェクトは同じタイプになります。
このようなウィザードの例としては、複数の部品を作成できるようなウィザードがあります。このウィザードは、以下の 3 つのステップで構成されます。
1. 部品の定義
ユーザーは、作成する部品のタイプと、作成されるすべての部品に共通するその他の属性を入力します。
2. 属性の設定
ユーザーは、作成する各部品の名前と数を表形式で入力します。この表は、ユーザーが任意の数の部品を入力できる動的な表です。
3. 追加属性の設定
ユーザーは、すべての部品に共通する追加の属性を入力します。
ユーザーが 5 つの部品のデータを入力すると、DefaultObjectFormProcessorController は 5 つの ObjectBeans を生成します。各 ObjectBean は、それが表す部品に特有のステップ 2 のデータを含み、また、ステップ 1 とステップ 3 のデータを含みます。部品間に関係はなく、各部品は独立して作成できるため、どの ObjectBeans も親および子を持ちません。すべての ObjectBeans の処理には同じ ObjectFormProcessor と ObjectFormProcessorDelegates が使用され、どのオブジェクトも同じタイプなので、これらのオブジェクトは同じ ProcessorBean に配置されます。
関連する複数のターゲットオブジェクト
ウィザードによっては、関連のある複数のターゲットオブジェクトを含めることができます。たとえば、変更通知を作成し、その変更通知に関連する変更タスクを作成するウィザードを生成できます。変更通知と変更タスク間に関連性を生成するには、変更通知のプロセッサに、オブジェクト間にどのような関連性を生成するのかを指示する必要があります。
変更通知 ObjectBean には 3 つの子 ObjectBeans があります。変更タスク ObjectBeans は親 ObjectBean のみを持ち、子はありません。
この場合、ObjectBeans の構造を作成するために独自の FormProcessorController を記述する必要があります。これには、DefaultFormProcessorController のサブクラスを指定しても構いません。
デフォルトコントローラは、これらの ObjectBeans を作成します。その createObjectBeanStructure() メソッドはオーバーライドされ、すべての ObjectBeans のフラットリストが与えられる場合があります。そのメソッドでは、ObjectBeans の親と子を設定します。すべてのルート ObjectBeans のリストを戻します。ObjectBean 構造を作成した後、DefaultFormProcessorController は、ObjectBeans を以下のように ProcessorBeans にグループ化する ProcessorBean.newCollection() メソッドを呼び出します。
上図の円は ObjectBeans を表し、実線はそれらの関連性を表します。長方形は 2 つの ProcessorBeans を表し、点線はそれらの関連性を表します。
各 ProcessorBean には、その中のオブジェクトに必要な ObjectFormProcessor と ObjectFormProcessorDelegates の独自のインスタンスが格納されます。ルート ProcessorBean のプロセッサが "ProcessorInstance1" で、子 ProcessorBean のプロセッサが "ProcessorInstance2" である場合、プロセッサメソッドは、以下の要領で呼び出されます。
| メソッド | 実行されるタスク |
1 | ProcessorInstance1.preProcess(ProcessorBean 1 内の ObjectBean) | WTChangeOrder2 オブジェクトのインスタンスを 1 つ作成し、これを ObjectBean の object 属性に保存する。 |
2 | ProcessorInstance2.preProcess(ProcessorBean 2 内の ObjectBean) | WTChangeActivity2 オブジェクトのインスタンスを 3 つ作成し、これらを ObjectBean の object 属性に保存する。 |
3 | ProcessorInstance1.doOperation(ProcessorBean 1 内の ObjectBean) | WTChangeOrder2 オブジェクトを永続化する。 |
4 | ProcessorInstance2.doOperation(ProcessorBean 2 内の ObjectBean) | WTChangeActivity2 インスタンスを永続化する。 |
5 | ProcessorInstance1.postProcess(ProcessorBean 1 内の ObjectBean) | 変更通知と変更タスク間の関連付けを生成する。 |
6 | ProcessorInstance2.postProcess(ProcessorBean 2 内の ObjectBean) | なし |
7 | ProcessorInstance1.postTransactionProcess(ProcessorBean 1 内の ObjectBean) | なし |
8 | ProcessorInstance2.postTransactionProcess(ProcessorBean 2 内の ObjectBean) | なし |
以上のタスクを実行する場合、ある程度の自由度があります。たとえば、メソッド 5 の代わりにメソッド 6 で関連付けを生成しても、影響はありません。あるいは、ObjectFormProcessorDelegate を作成し、その postProcess() メソッドで関連付けを作成することもできます。フレームワークには、ウィザードに合うように、コードをモジュール化できる柔軟性があります。以上のタスクは、主要トランザクションの開始点と終了点を守って行ってください。
ObjectBeans の構造はもっと複雑な場合があります。以下に例を示します。
上図のように、以下の条件が当てはまる場合、ObjectBeans は、異なる ProcessorBeans クラスに配置されます。
• ObjectBeans 内のオブジェクトが互いに異なるタイプである
• ObjectBeans によって ObjectFormProcessor が異なる
(注記: この時点では、ウィザードのすべての ObjectBeans の ObjectFormProcessor は同じでなければなりません)
• ObjectBeans によって ObjectFormProcessorDelegates のリストが異なる
• ObjectBeans によって親 ObjectBean が異なる
DefaultFormProcessorController は、ツリーのルート ProcessorBean からリーフ ProcessorBeans の順に、各 ProcessorBean に関連付けられているプロセッサを順番に呼び出していきます。
手順 - ウィザード処理コードの作成
ウィザード処理コードを作成する場合、以下の 2 つのオプションがあります。
• 1 つのターゲットオブジェクトが含まれたウィザード
• 複数のターゲットオブジェクトが含まれたウィザード
1 つのターゲットオブジェクトが含まれたウィザード
このプロセスは以下のステップで構成されます。
• プロセッサクラスの作成
• ウィザード操作に対するウィザードのプロセッサクラスの指定
• ウィザードに必要な ObjectFormProcessorDelegate クラスの作成
• ウィザードで使用する ObjectFormProcessorDelegate の指定
プロセッサクラスの作成
本製品には、オブジェクト作成を処理し、ウィザードを編集するための以下の 3 つのプロセッサが付属しています。
• com.ptc.core.components.forms.CreateObjectFormProcessor
• com.ptc.core.components.forms.DefaultEditFormProcessor
• com.ptc.core.components.forms.EditWorkableFormProcessor
これらのプロセッサはそのまま使用するか、または目的に合わせて拡張できます。
オブジェクト作成やウィザード編集を目的とする以外のウィザードの場合は、独自の ObjectFormProcessor を作成する必要があります。ObjectFormProcessors では、DefaultObjectFormProcessor クラスを拡張してください。
フォーム処理ロジックは、必要に応じて、このプロセッサの preProcess()、doOperation()、postProcess()、および postTransactionProcess() メソッドに配置してください。メソッドでは、DefaultObjectFormProcessor の対応するスーパーメソッドを呼び出してください。これによって、ObjectFormProcessorDelegates の呼び出しが処理されます。これらのメソッドには、ウィザードから収集されたすべてのフォームデータを格納する 1 つの ObjectBean が渡されます。フォームデータには、そのオブジェクトの getter メソッドを使用してアクセスできます。次に示す getter メソッドが一般的に使用されます。
public Map<String,List<String>> getChangedComboBox()
public Map<String,String> getChangedRadio()
public Map<String,String> getChangedText()
public Map<String,String> getChangedTextArea()
public Map<String,List<String>> getChecked()
public Map<String,List<String>> getUnChecked()
public List getRemovedItemsByName(String paramName)
public List getAddedItemsByName(String paramName)
public String getTextParameter(String key)
public String[] getTextParameterValues String key)
詳細については、Javadoc を参照してください。
ObjectBean の "object" 属性は、ターゲットオブジェクトのインスタンスを表します。下流のメソッドで使用できるように、必要に応じて、いずれかのプロセッサメソッド (preProcess() など) によって object 属性を設定してください。その他の情報は、プロセッサインスタンス変数を使用してメソッド間で受け渡しできます。
これらのメソッドに渡された NmCommandBean オブジェクトには、ウィザードが起動したページに関する情報や、ウィザードが起動したときに親ページで選択されたオブジェクトに関する情報が含まれています。また、すべての HTML フォームデータも含まれていますが、そのデータにアクセスする場合は、NmCommandBean ではなく ObjectBean に対してメソッドを使用してください。NmCommandBean の詳細については、Javadoc を参照してください。
preProcess()、doOperation()、postProcess()、および postTransactionProcess() メソッドの結果は、com.ptc.core.component.FormResult オブジェクトを使用して DefaultFormProcessorControllerに返します。結果が返される前に、これらの各メソッドによって FormResult.setStatus() が呼び出され、処理ステータスが返されます。次の 3 つのオプションを使用できます。
• FormProcessingStatus.SUCCESS - エラーなしでメソッドが実行された場合
• FormProcessingStatus.FAILURE - メソッドの実行で致命的なエラーが発生した場合。FormProcessingStatus.NON_FATAL_ERROR - メソッドは正常に実行されたが、ユーザーに対する報告が必要な 1 つまたは複数の問題が発生した場合。
DefaultFormProcessorController は、返された FormResult をその continueExecuting() メソッドに渡し、次の処理段階に進むか、中断するかを決定します。デフォルトでは、ステータスが FormProcessingStatus.FAILURE となった場合にのみ処理が中断されます。処理が中断するか、すべての処理が正常に完了した場合、コントローラは、ObjectFormProcessor の setResultNextAction() メソッドを呼び出して、ブラウザに返されたレスポンスページを作成するために必要な情報を FormResult に設定します。
このメソッドは、以下の情報を提供します。
• フィードバックメッセージをユーザーに表示するかどうか (該当する場合)。
feedbackMessages および exceptions 変数から決定されます。
フィードバックメッセージは、ウィンドウ操作または指定された javascript を実行する前に表示されます (該当する場合)。
例外メッセージはステータスが FormProcessingStatus.FAILURE または FormProcessingStatus.NON_FATAL_ERROR の場合にのみ表示されます。
FormResult クラスと FormProcessingStatus クラスの詳細については、Javadoc を参照してください。
また、ObjectFormProcessor クラスの preProcess()、doOperation()、postProcess()、および postTransactionProcess() メソッドを使用して例外をスローすることもできます。その場合、ActionController に制御が戻り、FormResult の変数が以下のように設定されます。
• status - FormProcessingStatus.FAILURE
• exceptions - スローされた例外
これにより、レスポンスページでアラートウィンドウに例外メッセージが表示され、ウィザードウィンドウが閉じます。
選択されたオブジェクトを NmCommandBean を使ってフォームプロセッサで取得する方法
フォーム処理シナリオは 4 種類あり、各シナリオで選択された oid を取得するには、使用できる NmCommandBean に対する API が異なります。詳細については次の図を参照してください。
ウィザード操作に対するウィザードのプロセッサクラスの指定
ウィザードの <action> タグの <command> サブタグ内で、ObjectFormProcessor クラスを指定します。action タグは *actions.xml ファイル内に格納されます。
次に示すサンプルコードでは、プロセッサとして CreateDocFormProcessor クラスを指定します。
<action name="create">
<command
class="com.ptc.core.components.forms.CreateObjectFormProcessor"
windowType="popup" />
</action>
ウィザードに必要な ObjectFormProcessorDelegate クラスの作成
ObjectFormProcessorDelegates は、ウィザード処理において 1 つまたは複数のサブタスクを実行するために使用されることがあります。複数の ObjectFormProcessors が同じ委任クラスを呼び出す可能性もあるので、複数のウィザードで必要となるタスクについては、通常、ObjectFormProcessorDelegate クラスが使用されます。以下に、本製品に添付されている ObjectFormProcessorDelegates の使用例について説明します。
• いくつかのオブジェクト作成ウィザードには、「チェックイン後にチェックアウト状態を保持」というチェックボックスがあります。オブジェクト作成後、チェックボックスがオンにされると、これらすべてのウィザードの ObjectFormProcessors は同じ ObjectFormProcessorDelegate クラスを呼び出してこのチェックボックスを処理し、オブジェクトをチェックアウトします。
• 通常、ContentHolders オブジェクトを作成するウィザードは、オブジェクトに付加するドキュメントを指定する「添付資料を設定」ステップを持ちます。これらのウィザードはいずれも同じ ObjectFormProcessorDelegate クラスを呼び出して、添付資料の永続性を処理します。
• 多くのオブジェクト作成ウィザードには、オブジェクトのフォルダを指定するための Location 属性の入力フィールドがあります。この入力フィールドの処理は複雑なので、これらのウィザードはいずれも同じ ObjectFormProcessorDelegate を呼び出して、作成されるオブジェクトについてフォルダを設定します。
上記の例に示したように、ObjectFormProcessorDelegate は、1 つまたは複数の入力フィールドを処理できます。複数のウィザードで使用されている HTML エレメントを、作成するウィザードに含めない場合、委任は必要ありません。ただし、委任は、処理コードのモジュール化にも役立てることができます。
ObjectFormProcessorDelegates では、DefaultObjectFormProcessorDelegate クラスを拡張してください。ObjectFormProcessorDelegates は DefaultFormProcessorController によってインスタンス化されて ObjectFormProcessor に渡されます。
ObjectFormProcessorDelegates には ObjectFormProcessors と同様に preProcess()、doOperation()、postProcess()、postTransactionProcess() メソッドがあります。ウィザードについて登録された委任は、さまざまな処理段階で DefaultObjectFormProcessor によって呼び出されます。
ObjectFormProcessor メソッドの結果が FormProcessorController に渡されるのと同様に、ObjectFormProcessorDelegate メソッドの結果は、FormResult を使用して ObjectFormProcessor に渡されます。
ObjectFormProcessor メソッドと同様に、ObjectFormProcessorDelegate メソッドで例外をスローすることができます。これらの処理方法は、例外を呼び出す ObjectFormProcessor によって異なります。
ウィザードで使用する ObjectFormProcessorDelegate の指定
DefaultObjectFormProcessor によってインスタンス化される ObjectFormProcessorDelegate クラスの名前は、必要に応じ、以下の方法で非表示入力フィールドでやり取りされます。
<input name="FormProcessorDelegate"
value="com.ptc.core.components.forms.NumberPropertyProcessor"
type="hidden">
これらの非表示入力フィールドは、複数の方法で作成できます。
• 具体的なウィザードステップが委任に関連付けられている場合、この委任は、ウィザードステップ操作の command サブタグ内で指定できます。例:
<action name="attachmentsWizStep" postloadJS="preAttachmentsStep"
preloadWizardPage="false"
<command
class="com.ptc.windchill.enterprise.attachments.forms.Second
aryAttachmentsSubFormProcessor" windowType="wizard_step"/>
</action>
次にウィザードフレームワークは、このステップを使用し、任意のウィザードについて非表示 FormProcessorDelegate フィールドを生成します。ウィザードステップ操作についてオブジェクトハンドルを指定した場合、そのステップに関連付けられているターゲットオブジェクトについてのみ委任が呼び出されるように、非表示フィールドの名前属性にそのオブジェクトハンドルが格納されます。
• 委任を必要とする入力フィールドを配置する場合は、その入力フィールドについて GUI コンポーネントを作成するデータユーティリティを使用して非表示フィールドを生成できます。addHiddenField() メソッドと AbstractRenderer を利用するために、データユーティリティで AbstractGuiComponent のサブクラスを返してください。データユーティリティで GUI コンポーネントを作成した後、AbstractGuiComponent クラスの addHiddenField() メソッドを呼び出します。例:
LocationInputGuiComponent guiComponent = new
LocationInputComponent(…);
guiComponent.addHiddenField
(CreateAndEditWizBean.FORM_PROCESSOR_DELEGATE, "com.
ptc.windchill.enterprise.folder.LocationPropertyProcess
or");
非表示入力フィールドは、AbstractRenderer によって自動的に生成されます。非表示入力フィールドがステップに関連付けられているか、またはオブジェクトハンドルが含まれたテーブル行に関連付けられている場合、そのオブジェクトハンドルは、非表示フィールドの HTML 名属性に埋め込まれます。AbstractGuiComponent を拡張しない GUI コンポーネントを返すようにした場合は、必要な非表示フィールドのレンダリング方法を GUI コンポーネントとレンダラーに指示する必要があります。
• 委任の非表示フィールドは、jsp ファイルに直接含めることができます。ただし、非表示フィールドにその関連 HTML 入力フィールドがカプセル化されるので、最初の 2 つの方法のうち、いずれかをお勧めします。
複数のターゲットオブジェクトが含まれたウィザード
このプロセスは以下のステップで構成されます。
• プロセッサクラスの作成
• ウィザード操作に対するウィザードのプロセッサクラスの指定
• ウィザードに必要な ObjectFormProcessorDelegate クラスの作成
• ウィザードで使用する ObjectFormProcessorDelegate の指定
• FormProcessorController の作成 (必要に応じて)
• ウィザードで使用する FormProcessorController の指定 (必要に応じて)
プロセッサクラスの作成
1 つのターゲットオブジェクトが含まれたウィザードの場合と方法は同じです。プロセッサクラスの作成を参照してください。
ウィザード操作に対するウィザードのプロセッサクラスの指定
1 つのターゲットオブジェクトが含まれたウィザードの場合と方法は同じです。ウィザード操作に対するウィザードのプロセッサクラスの指定を参照してください。
ウィザードに必要な ObjectFormProcessorDelegate クラスの作成
1 つのターゲットオブジェクトが含まれたウィザードの場合と方法は同じです。ウィザードに必要な ObjectFormProcessorDelegate クラスの作成を参照してください。
ウィザードで使用する ObjectFormProcessorDelegate の指定
1 つのターゲットオブジェクトが含まれたウィザードの場合と方法は同じです。ウィザードで使用する ObjectFormProcessorDelegate の指定を参照してください。特定のオブジェクトについてのみ委任を使用する場合は、その委任を指定する非表示フィールドの名前属性にオブジェクトハンドルを埋め込む必要があります。
FormProcessorController の作成 (必要に応じて)
ウィザードのターゲットオブジェクトが関連オブジェクトの構造を形成している場合、ObjectBeans の構造を作成するために独自の FormProcessorController を作成する必要があります。フォームデータを ObjectBeans と ProcessorBeans に分割し、フォームプロセッサを呼び出す DefaultFormProcessorController の機能を使用するには、このクラスをサブクラス化してください。通常、オーバーライドしなければならない唯一のメソッドは createObjectBeanStructure() メソッドです。
ウィザードで使用する FormProcessorController の指定 (必要に応じて)
独自の FormProcessorController を作成した場合は、ウィザードのメイン JSP ファイルの wizard タグ内でこのコントローラをウィザードで使用するように指定してください。次に例を示します。
<jca:wizard helpSelectorKey="change_createProblemReport"
buttonList="DefaultWizardButtonsWithSubmitPrompt"
formProcessorController="com.ptc.windchill.enterprise.change2.forms.
controllers.ChangeItemFormProcessorController">
FormResult/クライアント側でのフォームの後処理
Windchill 10.1 MR010 以降のリリースでは、フォーム処理と操作応答処理が区別されています。つまり、フォームプロセッサは選択した/影響を受けるオブジェクトを更新/追加/削除する作業を実行しますが、FormResult に対する次の操作を指定する必要はありません。FormResult には更新/追加/削除されたオブジェクトの OID が格納されます。これらの OID はクライアントに戻され、クライアントはこれらのオブジェクトを現在表示しているコンポーネントを更新します。
FormResult の設定
Windchill 10.1 MR010 以降のリリースでは、次の操作 (setNextAction(FormResultAction.REFRESH_OPENER)) を設定する必要がありません。追加/更新/除去されたオブジェクトの OID だけを FormResult オブジェクトに追加する必要があります。
例: formResult.addDynamicRefreshInfo new DynamicRefreshInfo(newOid, oldOid, NmCommandBean.DYNAMIC_UPD))
FormResult に対して URL または Javascript 関数を設定する機能は有効なままとなります。ただし、これはその他のオプションが使用できない場合にだけ実行する必要があります。これらの操作は複数のクライアントから実行されている可能性があるため、返された URL Javascript が適切でなかったり有効なコードを参照していなかったりすることがあります。個々の操作によってページ上のコンポーネントを更新するのではなく、コンポーネントが独自に更新するのが理想的です。FormResult で URL が設定されている場合、操作が開始されたコンポーネントで afteraction リスナーは呼び出されません。ただし、objectsaffected リスナーが呼び出されます。
JCA コンポーネントの再表示/更新
操作を介して更新されたオブジェクトコンポーネントに関連付け可能な 2 つのリスナーがあります。ほとんどのコンポーネント (テーブル、ツリー、情報ページなど) には両方のイベント用にデフォルトのリスナーがあります。
• afteraction: このリスナーは、操作の開始/実行元のコンポーネント内のオブジェクトを更新します。たとえば、情報ページからチェックアウト操作が実行された場合、情報ページの afteraction リスナーがその情報ページを再表示します。同様に、チェックアウト操作がテーブルから開始された場合、テーブルの afteraction リスナーがテーブルの行を更新します。このリスナーは afteraction イベントリスナーを追加することによって任意の EXT コンポーネントに関連付けることができます。このリスナーは parameter.component.on(‘afteraction’, someAfterActionListener); として FormResult JS オブジェクトを受け取ります。
• objectsaffected: このリスナーは、操作が別のコンポーネントから実行された場合に、コンポーネント内のオブジェクトを更新します。たとえば、チェックアウト操作が情報ページから実行され、サーチ結果テーブルにそれと同じオブジェクトが含まれている場合、サーチ結果テーブルの objectsaffected リスナーがそのテーブルの行を更新します。このリスナーはグローバル PTC.action オブジェクト component.mon(PTC.action, ‘objectsaffected’,someListener); に関連付けられます。
カスタム操作処理の例
コンポーネント内でいずれかの操作が行われた場合のコンポーネント全体の再表示
me.on('afteraction', me.onAfterAction);
me.onAfterAction = function(formResult) {
me.refresh();
return true;//Stop further processing
};
FormResultAction.FORWARD と LOAD_OPENER_URL の置き換え
コンポーネントによって動作は異なり、クライアントプラットフォームによって URL パターンは異なるため、FormResult に包括的に URL を指定することはサポートされていません。各コンポーネントはその方法を個別に決定でき、infopage や miniNavigator などの一般的なコンポーネントの afterAction リスナーには、これらのコンポーネントを再表示するための一般的なロジックがすでに備わっています。たとえば、miniNavigator は新規 URL に移動するとユーザーが現在のコンテキストから外れるため、代わりにそれ自体を再表示します。
コンポーネント固有のイベントリスナーに一意の操作を実行させる方法については、次のチェックアウトの例を参照してください。js ファイル内のコード PTC.miniNavigator.onAfterAction および PTC.infoPage.onAfterAction を参照してください。クライアント側で URL を構築するために追加の URL パラメータが必要な場合、FormResult.extraData マップを使用して追加情報を渡すことができます。
特定のテーブルにおけるオブジェクトの処理方法を変更できます。たとえば、(wip.jsfrag から) 既存の行にチェックアウトグリフを追加する代わりに、チェックアウトテーブルに行を追加します。
PTC.wip = {};
/**
* add/remove rows from the checkouts table for the wip actions
*/
PTC.wip.checkoutsTableObjectsAffectedWrapper = function(original, formResult) {
if (formResult.actionName === 'checkout') {
var added_new_rows = formResult.getUpdatedOids();
if(added_new_rows.length > 0) {
clearActionFormData();
rowHandler.addRows(added_new_rows, this.id, null, {
doAjaxUpdate : true,
addSorted : true
});
}
return true;
}
return original.call(this, formResult);
};
PTC.wip.addCheckoutTableListeners = function (table) {
table.onObjectsAffected = table.onObjectsAffected.wrap
(PTC.wip.checkoutsTableObjectsAffectedWrapper);
};
Ext.ComponentMgr.onAvailable('checkedout.work.table',
PTC.wip.addCheckoutTableListeners);
FormResultAction.JAVASCRIPT の置き換え
ある操作の結果としてページ内の特定のコンポーネントを更新するために追加の Javascript を実行する必要がある場合、代わりに、次の例に示すチェックアウト操作などの特定の操作に反応する、コンポーネント固有の objectsaffected リスナーを追加するほうが適切です。ほかのページでは Javascript が必要でないことがよくあるため、一部のウィザードではそのウィザード固有のリスナーを追加します。
ウィザード固有のハンドラ
ウィザードの結果としてカスタム (固有の) コードを実行する必要がある操作では、成功したサブミットを処理するためのコールバック関数を使用できます。この successFunc コンフィギュレーションパラメータは PTC.wizard.submitWizard 関数に渡されます。この successFunc は、ウィザードがサーバーから FormResult を受信して afteraction イベントと objectsaffected イベントを発生させたときに呼び出されます。これにより、操作のオーナーはウィザードの流れと動作をより細かく制御でき、個々のコンポーネントによるイベント名の処理方法を修正する必要がありません。たとえば、編集ウィザードの checkin ボタンには、属性がデータベースに正常に保存されると checkin ウィザードを開始する成功ハンドラがあります。
次に示すサンプルコードで、ウィザードのコードに渡される関数に注意してください。
<command onClick="onEditSubmit('checkinButton')"/>
function onEditSubmit(actionName){
var params = {successFunc: PTC.wizard.launchCheckinWizard,
finished: actionName=='saveButton'};
PTC.wizard.submitWizard(params);
}
特定のテーブルにおけるオブジェクトの処理方法の変更
たとえば、(wip.jsfrag から) 既存の行にチェックアウトグリフを追加する代わりに、チェックアウトテーブルに行を追加できます。
PTC.wip = {};
/**
* add/remove rows from the checkouts table for the wip actions
*/
PTC.wip.checkoutsTableObjectsAffectedWrapper =
function(original, formResult) {
if (formResult.actionName === 'checkout') {
var added_new_rows = formResult.getUpdatedOids();
if(added_new_rows.length > 0) {
clearActionFormData();
rowHandler.addRows(added_new_rows, this.id, null, {
doAjaxUpdate : true,
addSorted : true
});
}
return true;
}
return original.call(this, formResult);
};
PTC.wip.addCheckoutTableListeners = function (table) {
table.onObjectsAffected = table.onObjectsAffected.wrap
(PTC.wip.checkoutsTableObjectsAffectedWrapper);
};
PTC.onAvailable('checkedout.work.table',
PTC.wip.addCheckoutTableListeners);
FormResultAction.FORWARD と LOAD_OPENER_URL の置き換え
コンポーネントによって動作は異なり、クライアントプラットフォームによって URL パターンは異なるため、FormResult に包括的に URL を指定することはサポートされていません。各コンポーネントはその方法を個別に決定でき、infopage や miniNavigator などの一般的なコンポーネントの afterAction リスナーには、これらのコンポーネントを再表示するための一般的なロジックがすでに備わっています。たとえば、miniNavigator は新規 URL に移動するとユーザーが現在のコンテキストから外れるため、代わりにそれ自体を再表示します。
コンポーネント固有のイベントリスナーに一意の操作を実行させる方法については、次のチェックアウトの例を参照してください。js ファイル内のコード PTC.miniNavigator.onAfterAction および PTC.infoPage.onAfterAction も参照してください。クライアント側で URL を構築するために追加の URL パラメータが必要な場合、FormResult.extraData マップを使用して追加情報を渡すことができます。ほとんどの場合、作成または修正されたオブジェクトの情報ページに自動転送する必要はありません。作成処理の後、新規オブジェクトの情報ページへのリンクを含むインラインメッセージが表示されます。この方法によって操作後の自動転送が可能となります。コンポーネントの onAfterAction メソッドを修正して次のコードシーケンスを追加します。
if (formResult.actionName === 'checkout') {
PTC.infoPage.goTo(formResult.getUpdatedOids()[0]);
}
return true;
特定の操作で自動転送する可能なすべてのコンポーネントに、一般的な操作ハンドラを追加できます。次のサンプルコードにこの詳細を示します。ただし、一部のページとコンポーネントでは進行中のデータが失われる可能性があるため、この操作は必ずしも実行する必要はありません。
PTC.action.on('objectsaffected', function (formResult) {
if (formResult.actionName === 'checkout') {
PTC.infoPage.goTo(formResult.getUpdatedOids()[0]);
}
return true;
});
制限事項
• 現在、ウィザード 1 つにつきサポートされているクラスは ObjectFormProcessor クラス 1 つだけです。
• 表形式でないかぎり、このフレームワークでは、同じウィザードステップの複数のオブジェクトについてデータを使用することはできません。また、このフレームワークでは、同じステップのすべてのオブジェクトに共通のデータを、オブジェクト固有のデータとして使用することもできません。
その他のリソース
関連パッケージ/クラスの Javadoc
• com.ptc.core.components.forms.FormDispatcher
• com.ptc.core.components.forms.FormProcessorController
• com.ptc.core.components.forms.DefaultFormProcessorController
• com.ptc.core.components.forms.ObjectFormProcessor
• com.ptc.core.components.forms.DefaultObjectFormProcessor
• com.ptc.core.components.forms.CreateObjectFormProcessor
• com.ptc.core.components.forms.DefaultEditFormProcessor
• com.ptc.core.components.forms.EditWorkableFormProcessor
• com.ptc.core.components.forms.ObjectFormProcessorDelegate
• com.ptc.core.components.forms.DefaultObjectFormProcessorDelegate
• com.ptc.core.components.forms.FormResult
• com.ptc.core.components.forms.DynamicRefreshInfo
• com.ptc.core.components.forms.FormProcessingStatus
• com.ptc.core.components.util.FeedbackMessage
• com.ptc.core.ui.resources.FeedbackType