この章では、SRDemoアプリケーションのSRService
を例として使用し、アプリケーション・モジュールのアクティブ・データ・モデルおよびビジネス・サービス・インタフェース・メソッドが、設計時にデータ・バインディングのドラッグ・アンド・ドロップ用にどのように表示されるか、および実行時にアプリケーション・モジュールのデータ・コントロールを使用してADF Modelデータ・バインディング・レイヤーからどのようにアクセスできるかについて説明します。
この章の内容は次のとおりです。
Oracle ADF Modelレイヤーは、宣言的なデータ・バインディング機能です。ADF Modelレイヤーでは、ユーザー・インタフェース・テクノロジとビジネス・サービス実装の分離を可能にするJSR-227仕様の2つの概念(データ・コントロールと宣言的バインディング)が具体化されています。データ・コントロールおよび宣言的バインディングにより、統一化された設計時および実行時のアプローチを使用して、ユーザー・インタフェースをコード記述なしでバックエンド・ビジネス・サービスにバインドできます。
データ・コントロールでは、サービスの操作およびデータ・コレクションを記述する標準のメタデータ・インタフェースを使用して、ビジネス・サービスの実装テクノロジを抽象化します。このインタフェースには、プロパティ、メソッドおよび関連する型についての情報が含まれます。設計時に、JDeveloperのようなビジュアル・ツールで標準的なサービス・メタデータを操作し、データ・コントロール操作やデータ・コレクションへのUIコンポーネントのバインドを簡略化します。実行時に、汎用のOracle ADF Modelレイヤーによって、適切なXMLファイルからデータ・コントロールおよびバインディングを記述した情報が読み取られ、ユーザー・インタフェースとビジネス・サービスを結合する双方向の関係が実装されます。
宣言的なバインディングによって、データ・コントロール内のデータ・コレクションからのデータ・アクセスの詳細と、その操作の実行が抽象化されます。すべてのエンタープライズ・アプリケーションに必要とされるデータ・バインディングの主要な機能を自動化する宣言的なバインディング・オブジェクトには、次の3つの基本的な種類があります。
イテレータ・バインディング: データ・コレクションの現在の行を追跡するイテレータをバインド
値バインディング: データ・コレクションの属性へのUIコンポーネントの関連付け
アクション・バインディング: カスタム操作または組込み操作をデータ・コントロールまたはそのデータ・コレクションで実行
イテレータ・バインディングを使用すると、データ・コレクションのスクロール処理やページ移動、または概要情報から詳細情報へのドリルダウンを可能にするユーザー・インタフェースを簡単に作成できます。データを表示するUIコンポーネントでは、値のバインディングを使用します。値バインディングは、単純なテキスト・フィールドで使用する最も基本的なものから、リスト、表、ツリーでのUIコントロールのニーズをサポートするような、より高度なリスト、表、ツリーのバインディングまで、様々な種類があります。アクション・バインディングは、メソッドを起動するハイパーリンクやボタンなどのUIコンポーネントによって使用されます。アクション・バインディングにより、ユーザーがコンポーネントをクリックすると、コードなしでビジネス・サービスが起動します。アクション・バインディングには、組込み操作を起動する通常のアクション・バインディングと、カスタム操作を起動するメソッド・アクション・バインディングの2種類があります。
アプリケーション・モジュールのデータ・コントロールは、Oracle ADFに付属する複数のデータ・コントロール実装のうちの1つです。その役目は、リクエスト開始時に使用可能なアプリケーション・モジュール・インスタンスを自動的に取得するアプリケーション・モジュール・プールのシン・アダプタとなることです。現在のリクエスト中に、アプリケーション・モジュールのデータ・コントロールにより、現在のユーザー・セッションのかわりに、アプリケーション・モジュール・インスタンスへの参照が保持されます。リクエスト終了時に、アプリケーション・モジュール・インスタンスは、アプリケーション・モジュールのデータ・コントロールによって解放され、プールに戻されます。ここで重要なことは、データ・コレクション、組込み操作およびサービス・メソッドに対してバインディング・オブジェクトが求めるインタフェースを、アプリケーション・モジュール・コンポーネントが直接実装することです。このため、バインディングでは、そのアクティブ・データ・モデル内のアプリケーション・モジュールおよびビュー・オブジェクトを直接操作できます。この最適化された対話では、特に、次のバインディングが可能になります。
任意のビュー・オブジェクト・インスタンスのデフォルト行セットのデフォルト行セット・イテレータに直接バインドするイテレータ・バインディング
次のいずれかに直接バインドするアクション・バインディング
アプリケーション・モジュールのクライアント・インタフェース上のカスタム・メソッド
アプリケーション・モジュールの組込み操作およびビュー・オブジェクト
図10-2は、アプリケーション・モジュールのデータ・コントロールが果すプール管理ロールを示し、バインディングとアプリケーション・モジュール・インスタンスの間の直接リンクを説明しています。
設計時に、データ・コントロール・パレットを使用して、JSF、JSP/StrutsおよびSwingアプリケーションのデータ・バインディングのドラッグ・アンド・ドロップを実行します。ワークスペースの各アプリケーション・モジュールは、データ・コントロール・パレットに自動的に表示されます。この項では、SRDemoアプリケーションのSRService
アプリケーション・モジュールを例として使用し、特に、独自のアプリケーション・モジュールの操作時のデータ・コントロール・パレットでの正確な表示について説明します。
図10-3は、SRDemoアプリケーションのビジネス・サービス・レイヤーを実装するSRService
アプリケーション・モジュールを示しています。このデータ・モデルには、複数のマスター/ディテール階層など、多数のビュー・オブジェクト・インスタンスが含まれています。デモのビュー・レイヤーはJSFページで構成され、このページのUIコンポーネントは、SRService
のアクティブ・データ・モデル内のビュー・オブジェクト・インスタンスのデータと、そのクライアント・インタフェース上の組込み操作およびサービス・メソッドにバインドされています。10.6項「SRDemoページでのSRServiceの使用方法の概要」では、各ページでこのアプリケーション・モジュールのどの部分が使用されるかが詳しく説明されます。
デフォルトでは、アプリケーション・モジュールはデータ・コントロール・パレットにAppModuleName
DataControl
という名前のデータ・コントロールとして表示されます。たとえば、SRService
の元の名前はSRServiceDataControl
でした。デフォルトのデータ・コントロール名を短くする、またはより適した名前に変更するには、次の手順を実行します。
アプリケーション・モジュール名を変更する方法:
アプリケーション・モジュールをアプリケーション・モジュール・エディタで開きます。
「カスタム・プロパティ」ページを開きます。
「名前」コンボ・ボックスで、ドロップダウン・リストからDATA_CONTROL_NAME
プロパティを選択します。
任意のデータ・コントロール名を「値」フィールドに入力し、「OK」をクリックしてウィザードを閉じます。
図10-4は、SRService
のデータ・コントロール名を、デフォルトのSRServiceDataControl
から、アプリケーション・モジュールの名前に応じた短いSRService
名に変更したカスタム・プロパティ設定を示しています。変更は、データ・コントロール・パレットに即時に反映されます。
アプリケーション・モジュールからアプリケーション・ページまたはパネルへのデータのバインディングを開始すると、アプリケーション・モジュールのデータ・コントロール名が、ユーザー・インタフェース・プロジェクトのDataBindings.cpx
ファイルと、データ・バインディングの各ページ定義XMLファイルに表示されます。また、アプリケーション・モジュールのサービス・インタフェースをプログラムで操作する必要がある場合は、コードでデータ・コントロール名を参照できます。このため、アプリケーション・モジュールの名前を変更する予定がある場合は、ビュー・レイヤーを作成する前にこの変更を行うことをお薦めします。
注意: JDeveloperリリース3では、アプリケーション・モジュールのデータ・コントロール名を1つ以上のページで参照した後に変更することにした場合、それが参照されているページ定義ファイルを開き、元の名前を新しい名前に手動で更新する必要があります。JDeveloperの今後のリリースでは、このリファクタ・サポートを拡張し、データ・コントロール名の変更が容易になる予定です。 |
図10-5は、SRService
のアクティブ・データ・モデル内のビュー・オブジェクト・インスタンスがデータ・コントロール・パレットでどのように表示されるかを示しています。各ビュー・オブジェクト・インスタンスは、ビュー・オブジェクト・インスタンス名と対応する名前が付いたデータ・コレクションとして表示されます。データ・コレクションの階層構造に注目してください。この図では、わかりやすくするために、各ビュー・オブジェクトに表示されるツリー内の詳細の一部は省略されています。ビュー・オブジェクトのこれらの追加の詳細は、10.3.6項「データ・コントロール・パレットでのビュー・オブジェクトの表示」で説明します。データ・コントロール・パレットは、マスター・データ・コレクションの下にネストされたディテール・データ・コレクションを表示することで、アプリケーション・モジュールのデータ・モデル内のマスター/ディテール階層を示します。
データ・コントロール・パレットは、アプリケーション・モジュールのクライアント・インタフェース上の各カスタム・メソッドも、メソッド名と対応する名前が付いたデータ・コントロール・カスタム操作として表示します。メソッドが引数を受け入れると、その引数は、操作ノード内にネストされた操作パラメータとして「Parameters」フォルダに表示されます。
ビュー・オブジェクト・インスタンスをデータ・モデルに初めて追加するとき、インスタンス名を自分で入力していない場合には、ビュー・オブジェクト名に数値接尾辞が付加された名前が生成されます。たとえば、ServiceRequests
ビュー・オブジェクトのインスタンスをデータ・モデルに追加すると、デフォルトのビュー・オブジェクト・インスタンス名はServiceRequests1
になります。ビュー・オブジェクト・インスタンス名は、アプリケーション・モジュール・エディタの「データ・モデル」ページで簡単に変更できます。
データ・コントロール・パレット内のデータ・コレクションからアプリケーション・ページまたはパネルへデータのバインディングを開始すると、データ・コントロール名の他に、データ・コレクション名も、ADF Modelデータ・バインディング・レイヤーで使用されるページ定義XMLファイル内で参照されます。アプリケーション・モジュールのデータ・モデル内のビュー・オブジェクト・インスタンスの名前がこれらのデータ・コレクションの名前として使用されるため、データがバインドされたページの作成にその名前を使用する前に、ビュー・オブジェクト・インスタンスの名前が説明的であることを確認してください。
注意: JDeveloperリリース3では、ビュー・オブジェクト・インスタンス名を1つ以上のページで参照した後に変更することにした場合、それが参照されているページ定義ファイルを開き、元の名前を新しい名前に手動で更新する必要があります。JDeveloperの今後のリリースでは、このリファクタ・サポートを拡張し、ビュー・オブジェクト・インスタンス名の変更が容易になる予定です。 |
アプリケーション・モジュールのデータ・コントロールでは、図10-6に示すように、Commit
およびRollback
という名前の2つのデータ・コントロールの組込み操作を公開します。これらの操作は、実行時にデータ・バインディング・レイヤーによって起動されると、現在のアプリケーション・モジュール・インスタンスに関連付けられているTransaction
オブジェクトのcommit()
メソッドおよびrollback()
メソッドに委譲します。データ・コントロール・ツリー内の「Operations」フォルダでは、ビューを簡略化するために、データ・コレクションおよびカスタム操作がすべて省略されています。
注意: 多数のビュー・オブジェクト・インスタンスおよびカスタム・メソッドがあるアプリケーション・モジュールでは、データ・コントロールの直接の子ノードである「Operations」フォルダを見つけるには、データ・コントロール・パレット表示のスクロールが必要な場合があります。このフォルダに、その組込み操作が含まれています。 |
図10-7は、アプリケーション・モジュールのデータ・モデル内の各ビュー・オブジェクト・インスタンスがデータ・コントロール・パレットでどのように表示されるかを示しています。ビュー・オブジェクト属性は、対応するデータ・コレクションの直接の子ノードとして表示されます。この図のperformSearch()
メソッドのように、いずれかのカスタム・メソッドをビュー・オブジェクトのクライアント・インタフェースに表示することを選択している場合、そのメソッドは、同じレベルのビュー・オブジェクト属性のすぐ下にカスタム操作として表示されます。メソッドが引数を受け入れると、その引数は、ネストされた「Parameters」フォルダに操作パラメータとして表示されます。
図10-7に示すように、データ・コレクションの下の「Operations」フォルダには、そのコレクションで使用可能な組込み操作がすべて表示されます。操作で1つ以上のパラメータを受け入れると、そのパラメータは、ネストされた「Parameters」フォルダに表示されます。実行時に、これらのデータ・コレクション操作の1つがデータ・バインディング・レイヤーによって名前別に起動されると、アプリケーション・モジュールのデータ・コントロールは、組込み機能を処理するViewObject
インタフェース上の適切なメソッドにそのコールを委譲します。組込み操作は、現在の行に影響を与える操作、データ・コレクションをリフレッシュする操作、および他の全操作の3つのカテゴリに分類されます。
Create
: 現在の行になる新規行を作成。
Delete
: 現在の行を削除。
First
: 現在の行を行セット内の最初の行に設定。
Last
: 現在の行を行セット内の最後の行に設定。
Previous
: 現在の行を行セット内の前の行に設定。
Next
: 行を行セット内の次の行に設定。
Previous Set
: 1ページ前の行に移動。
Next Set
: 1ページ後の行に移動。
setCurrentRowWithKey:
パラメータとして渡された行キーのシリアライズされた文字列表現を使用して行の検索を試行。検出されると、それが現在の行になります。
setCurrentRowWithKeyValue:
パラメータとして渡された主キーの属性値を使用して行の検索を試行。検出されると、それが現在の行になります。
他のアプリケーション・モジュールのネストされたインスタンスを組み込んで複合アプリケーション・モジュールを作成すると、データ・コントロール・パレットではこのコンポーネント・アセンブリがツリー階層で表示されます。たとえば、SRDemoアプリケーションのoracle.srdemo.model.SRService
アプリケーション・モジュールの他に、同じパッケージに次のアプリケーション・モジュールも作成したとします。
ProductService
という名前のアプリケーション・モジュールを作成し、そのデータ・コントロール名をProductService
に変更
CompositeService
という名前のアプリケーション・モジュールを作成し、そのデータ・コントロール名をCompositeService
に変更
次に、OtherViewObject
およびAnotherViewObject
という名前の2つのビュー・オブジェクト・インスタンスをCompositeService
のデータ・モデルに追加し、アプリケーション・モジュール・エディタの「アプリケーション・モジュール」ページで、SRService
アプリケーション・モジュールのインスタンスおよびProductMaintenance
アプリケーション・モジュールのインスタンスを追加してこれらのインスタンスをCompositeService
の一部として再使用するとします。図10-8は、CompositeService
がデータ・コントロール・パレットでどのように表示されるかを示しています。SRServiceおよびProductServiceのネストされたインスタンスは、CompositeService
データ・コントロール内にネストされたパレット・ツリーに表示されます。ネストされたアプリケーション・モジュール・インスタンスによってクライアントに公開されるデータ・モデル全体および一連のクライアント・メソッドは、それらを再使用するCompositeService
の一部として自動的に使用可能になります。
SRService
およびProductService
のネストされたインスタンスをCompositeService
内で再使用していても、SRService
およびProductService
アプリケーション・モジュールもパレット・ツリー内の最上位データ・コントロール・ノードとして表示されることに注意してください。JDeveloperでは、SRService
またはProductService
がCompositeService
から独立した個別のデータ・コントロールとして使用される場合があると想定し、この3つすべてを表示します。正しいデータ・コントロールからデータ・バインディングのドラッグ・アンド・ドロップを実行するように注意してください。CompositeService
データ・コントロールに集約された部分である、ネストされたSRService
インスタンスのデータ・モデルのビュー・オブジェクト・インスタンスをページで使用する場合は、必ず、パレットでCompositeService
データ・コントロール・ノードの一部として表示されるデータ・コレクションを選択してください。
目的の用途に応じたドラッグ・アンド・ドロップ操作をすることが重要です。パレット内の最上位のSRService
データ・コントロール・ノードからデータ・コレクションをドロップすると、実行時に、SRService
コンポーネントのプールから取得されたSRService
アプリケーション・モジュールのインスタンスがページで使用されます。CompositeService
の一部であるSRService
のネストされたインスタンスからデータ・コレクションをドロップすると、実行時に、CompositeService
コンポーネントのプールから取得されたCompositeService
アプリケーション・モジュールのインスタンスがページで使用されます。各タイプのアプリケーション・モジュールのデータ・コントロールでは異なるトランザクションおよびデータベース接続が使用されるため、ネストされたアプリケーション・モジュールと最上位のデータ・コントロールの両方から不適切にデータ・コレクションを組み合せると、実行時に予期せぬ動作が発生します。事前に十分に注意してください。
「Create」ボタンを追加するには、データ・コレクションのCreate
操作をデータ・コントロール・パレットからJSPページまたはSwingパネルにドラッグ・アンド・ドロップします。
注意: 組込みCreate 操作は、WebベースのアプリケーションとSwingベースのデスクトップ・アプリケーションでは動作が異なります。Webアプリケーションでは、状況に応じて、CreateよりCreateInsert のほうが便利な場合があります。 |
データ・コレクションのCreate
操作をデータ・コントロール・パレットからJSPページにドラッグすると、JSFを使用するかどうかに関係なく、組込みCreate
操作に宣言的にバインドされているページ上に「Create」ボタンがドロップされます。Create
操作により、データ・コレクションの新規行が作成されますが、その行はデータ・コレクションの行セットには挿入されません。作成時に新規行を行セットに追加しないことで、新規行にデータを実際に入力する前にユーザーがこのページから移動した場合に、不要な空白行が他のページに表示されることを回避できます。Create
操作の起動後、イテレータ・バインディングでは、この新規行が現在の行であるかのようにこの行を一時的にポイントします。ユーザーが新規行の属性のデータを正常に送信した時点で、新規行が行セットに挿入されます。これは、ほとんどのWebアプリケーションのユースケースに最適な、宣言的な行作成アプローチです。
データ・コレクションのCreate
操作をデータ・コントロール・パレットからSwingパネルにドラッグすると、CreateInsert
という組込み操作に宣言的にバインドされているパネル上に「Create」ボタンがドロップされます。CreateInsert
操作により、データ・コレクションの新規行が作成され、その新規行が、コレクション内の現在の行の直前に挿入されます。CreateInsertは、Swingアプリケーションに最適なアプローチです。
Webアプリケーションでは、Create
のかわりにCreateInsert
を使用することが必要な場合があります。CreateInsertは、次の要素の作成時に使用します。
編集可能な表の制御
単一の現在編集可能な行が含まれる表
マスター/ディテール・ページ(新規作成したマスター行で既存のディテール行が表示されないようにする場合)
CreateInsert
は、新規行を行セットに挿入する必要がある場合に使用します。データ・コントロール・パレットには1つのCreate
操作のみが表示されるため、WebアプリケーションでCreateInsert
操作を使用するには、いくつかの追加手順が必要です。
Create操作をCreateInsertに変更する方法:
Create
操作をデータ・コントロール・パレットからページにドロップします。
ビジュアル・エディタでボタンを選択し、ポップアップ・メニューから「バインディングを編集」を選択します。
「アクション・バインディング・エディタ」で、「操作の選択」ドロップダウン・リストを使用して、アクション・バインディングでCreate
ではなくCreateInsert
を使用するように変更します。
Create
またはCreateInsert
操作を使用して新規行を宣言的に作成すると、次のコード行が暗黙的に実行されます。
// create a new row for the view object Row newRow = yourViewObject.createRow(); // mark the row as being "initialized", but not yet new newRow.setNewRowState(Row.STATUS_INITIALIZED);
また、CreateInsert
操作を使用している場合は、行を行セットに挿入する追加のコード行も実行されます。
// insert the new row into the view object's default rowset yourViewObject.insertRow(newRow);
行をエンティティ・ベースのビュー・オブジェクトに作成すると、現在のアプリケーション・モジュールに関連付けられているTransaction
オブジェクトによって、その処理が即時に記録されます。ビュー行の後に作成された新規エンティティ行は、Transaction
の保留中の変更リストにすでに含まれています。新しく作成した行の状態が初期化済とマークされている場合、その行はTransaction
の保留中の変更リストから削除され、エンド・ユーザーがまだデータ値を入力していない空白行とみなされます。新規行は、基礎となるエンティティ・オブジェクトで定義済のデフォルト値で初期化されてエンド・ユーザーに表示されるため、初期化済という用語はこの状態を表す適切な用語です。初期化済の行のどの属性にもユーザーがデータを入力していない場合は、その行が存在していないかのように処理されます。トランザクションのコミット時には、その行がTransaction
の保留中の変更リストに含まれていないため、INSERT
文はその行に対して試行されません。
初期化済の行に1つ以上の属性が設定されると同時に、初期化済の状態から新規状態(Row.STATUS_NEW
)に自動的に遷移します。この時点で、基礎となるエンティティ行はTransaction
の保留中の変更リストに登録され、トランザクションの次回コミット時に新規行が永続的に保存されます。
注意: 多数の初期化済の行を作成してもその行への移入を行わないアプリケーションを使用しながらエンド・ユーザーが手順を実行した場合、低速メモリー・リークが発生することがあります。しかし、心配は無用です。新規状態に遷移しない初期化済の行で使用されるメモリーは、Java仮想マシンのガベージ・コレクタによって最終的に解放されます。 |
ページの作成時は、Record 5 of 25などの、なんらかのレコード・ステータス・インジケータを表示すると便利な場合がよくあります。複数の行を1ページに表示するときは、Record 5-10 of 25などのバリアントを表示すると便利な場合もあります。このようなレコード・インジケータは、単純なテキスト・コンポーネントを使用して作成でき、各コンポーネントにより、EL式を使用してイテレータ・バインディングまたは表バインディングから適切な値が表示されます。イテレータ・バインディングのrangeSize
プロパティにより、ユーザー・インタフェースで表示可能なページごとの行数が定義されます。ページ定義にSomeViewIter
という名前のイテレータ・バインディングまたはSomeView
という名前の表バインディングが含まれている場合は、次のEL式を参照できます。
ページごとの行数
#{bindings.
SomeViewIter
.rangeSize}
#{bindings.
SomeView
.rangeSize}
合計行数
#{bindings.
SomeViewIter
.estimatedRowCount}
#{bindings.
SomeView
.estimatedRowCount}
現在のページの最初の行
#{bindings.
SomeViewIter
.rangeStart + 1}
#{bindings.
SomeView
.rangeStart + 1}
現在のページの最後の行
#{bindings.
SomeViewIter
.rangeStart + bindings.
SomeViewIter
.rangeSize}
#{bindings.
SomeView
.rangeStart + bindings.
SomeView
.rangeSize}
現在の行の番号
#{bindings.
SomeViewIter
.rangeStart + bindings.
SomeViewIter
.currentRowIndexInRange + 1}
#{bindings.
SomeView
.currentRowIndex + 1}
ビュー・オブジェクトに名前付きバインド変数がある場合、追加のExecuteWithParams
操作が、対応するデータ・コレクションの「Operations」フォルダ内に表示されます。図10-9に示すように、この組込み操作では名前付きバインド変数ごとに対応するパラメータを1つ受け入れます。たとえば、図のStaffListByEmailNameRole
ビュー・オブジェクトには、EmailAddress
、Role
、TheFirstName
およびTheLastName
という4つの名前付きバインド変数があるため、ExecuteWithParams
アクションに対してこれらと同じ名前のパラメータが表示されます。実行時に、ExecuteWithParams
組込み操作がデータ・バインディング・レイヤーによって名前別に起動されると、バインディング・レイヤーによって渡された個別のパラメータ値に名前付きバインド変数の値がそれぞれ設定され、ビュー・オブジェクトの問合せが実行されてその結果行セットがリフレッシュされます。
別のアプローチでは、同じく図10-9に示すように、ユーザーに設定を許可する引数を受け入れるビュー・オブジェクトのカスタムfinderメソッドを作成した後、ビュー・オブジェクト・エディタでビュー・オブジェクトのクライアント・インタフェースにこのメソッドを追加します。例10-1は、このようなカスタム・メソッドのコードを示しています。これは、SRDemoアプリケーションのStaffListByEmailNameRole
ビュー・オブジェクトから引用したものです。アプリケーション・モジュールのアクティブ・データ・モデルにより、メソッドではデータをクライアントに戻す必要がないことに注意してください。このメソッドにはvoid
戻り型があり、生成されたバインド変数のアクセッサ・メソッドsetEmailAddress()
、setRole()
、setTheFirstName()
およびsetTheLastName()
を使用して、メソッドに渡されたパラメータ値にバインド変数の値を設定します。次に、executeQuery()
をコールして、ビュー・オブジェクトの結果行セットをリフレッシュする問合せを実行します。
例10-1 ビュー・オブジェクトのカスタム・メソッドによる名前付きバインド変数の設定および問合せの実行
// From SRDemo Sample's StaffListByEmailNameRoleImpl.java public void findStaffByEmailNameRole(String email, String firstName, String lastName, String role) { setEmailAddress(email); setRole(role); setTheFirstName(firstName); setTheLastName(lastName); executeQuery(); }
この両方のアプローチでは、最終結果は同じになります。いずれも、データ・コントロール・パレットから検索フォームを作成する際に、同様に簡単に使用できます。この2つのアプローチの主な違いは次のとおりです。
組込み機能であるため、コードの記述が不要です。
操作をデータ・コントロール・パレットからドロップして、ADF検索フォームを作成でき、ユーザーが名前付きバインド変数の値に基づいてビュー・オブジェクトを検索できるようになります。
名前付きのバインド変数に対応する検索フィールドでは、ビュー・オブジェクト・コンポーネントの一部として定義可能なラベル・テキストに対するバインド変数のUIコントロール・ヒントを継承します。
カスタム・コードを多少記述する必要がありますが、最上位の操作の名前がデータ・コントロール・パレットに表示されることによって、検索操作の目的が明確になります。
カスタム操作をデータ・コントロール・パレットからドロップして、ADF検索フォームを作成でき、ユーザーがパラメータ値に基づいてビュー・オブジェクトを検索できるようになります。
メソッド引数に対応する検索フィールドでは、ビュー・オブジェクトの名前付きバインド変数自体に定義されるラベル・テキストのUIコントロール・ヒントを継承しません。このため、図10-10に示すように、メソッド引数に対応するページ定義変数のポップアップ・メニューの「プロパティ」を選択して、ラベル・テキストのUIコントロール・ヒントを定義する必要があります。
つまり、適切なアプローチを自分で判断できるように、両方のアプローチを覚えておくことをお薦めします。10.6.5項「SRStaffSearchページ」で説明されているように、StaffListByEmailNameRole
ビュー・オブジェクトには前述のfindStaffByEmailNameRole()
カスタム・メソッドが説明目的で含まれていますが、デモのJSFページでは宣言的なExecuteWithParams
組込みアクションを使用しています。
ADF Modelレイヤーでは、QBEをサポートするデータ・コレクションの操作時に、イテレータ・バインディングによって検索モードという機能がサポートされます。5.8項「Query-By-Exampleビュー基準を使用した結果のフィルタリング」で説明したとおり、ビュー基準行のビュー基準行セットが適用されている場合に、ビュー・オブジェクトでQBEがサポートされます。ビュー基準行は、ビュー・オブジェクトの行と同じ構造をしていますが、各属性のデータ型はString
であり、> 304
またはIN (314,326)
のような基準を検索基準として入力できます。
検索モード機能をサポートするために、イテレータ・バインディングには、ブール型findMode
プロパティがあり、デフォルトでfalse
に設定されています。図10-11に示すように、findMode
がfalse
の場合、イテレータ・バインディングは、データ・コレクション内のデータの行を含む行セットをポイントします。対照的に、findMode
をtrue
に設定すると、イテレータ・バインディングは、ビュー基準行の行セットをポイントするように切り替えられます。
バインディング・レイヤーでは、組込みデータ・コントロール操作を起動するアクション・バインディングは、ページ定義メタデータ内のイテレータ・バインディングに関連付けられます。このため、バインディング・レイヤーでCreate
やDelete
などの操作を実行時に正しいデータ・コレクションなどに適用することが可能になります。findMode
がfalse
に設定されているイテレータ・バインディングに対してCreate
やDelete
などの操作が起動されると、これらの操作は、データを含む行セットに影響を与えます。対照的に、findMode
がtrue
に設定されているイテレータ・バインディングに対して操作が起動されると、これらの操作はビュー基準行を含む行セットに影響を与え、QBE基準の行を効率的に作成または削除します。
組込みFind
操作を使用すると、イテレータ・バインディングのfindMode
フラグを切り替えることができます。イテレータ・バインディングのfindMode
がfalse
の場合、そのイテレータ・バインディングに対してFind
操作を起動すると、フラグがtrue
に設定されます。このイテレータに関連付けられている属性バインディングにバインドされているUIコンポーネントは、適宜、ビュー基準行セット内の現在のビュー基準行を表示するように切り替えられます。関連イテレータが検索モードの間にユーザーがUIコンポーネントの値を変更すると、その値はビュー基準行セット内のビュー基準行に適用されます。検索モードのイテレータにExecute
またはExecuteWithParams
組込み操作を起動すると、それぞれの操作によって検索モードがfalseに切り替えられた後、検索モード基準が適用され、データ・コレクションがリフレッシュされます。
イテレータ・バインディングのfindMode
がtrue
の場合、Find
操作を起動すると、検索モードがfalse
に設定され、ビュー基準行セット内のビュー基準行が削除されます。この結果、QBEモードが効率的に取り消されます。
ADF Controllerレイヤーでは、JSFページ・ライフサイクルとADF Modelデータ・バインディング・レイヤーが統合されます。この統合のカスタマイズは、アプリケーション全体でグローバルに行うか、ページごとに行うことができます。この項では、主に、SRDemoアプリケーションでこの2つの方法がどのように使用されているかについて、いくつかのヒントを示します。
ADFページ・ライフサイクルをグローバルにカスタマイズするには、次の処理を実行します。
oracle.adf.controller.faces.lifecycle.FacesPageLifecycle
を拡張するクラスを作成します。
ADFPhaseListener
の拡張とcreatePageLifecycle()
メソッドのオーバーライドを行ってカスタム・ページ・ライフサイクル・クラスのインスタンスを戻すクラスを作成します。
faces-config.xml
ファイルを、デフォルトのADFPhaseListener
ではなく、ADFPhaseListener
のサブクラスを使用するように変更します。図10-12に示すように、これは、JDeveloperのfaces-config.xml
エディタの「概要」タブの「Life Cycle」カテゴリで実行できます。
注意: 既存のADFPhaseListenerをADFPhaseListenerのカスタム・サブクラスと必ず置換してください。置換しないと、JSF/ADFライフサイクル調整がすべて2回実行されます。 |
SRDemoアプリケーションには、SRDemoPageLifecycle
クラスが含まれています。このクラスにより、ページ・ライフサイクルのreportErrors()
メソッドがグローバルにオーバーライドされ、ADF Modelレイヤーで捕捉およびキャッシュされた例外がJSFに報告されるデフォルトの方法が変更されます。この変更された実装では、ユーザーに報告される例外が、ユーザーが直接処理できる例外のみに削減され、エンド・ユーザーにはあまり意味のない追加のラップ例外が抑制されます。
単一ページのライフサイクルのカスタマイズは、pageDefinitionのControllerClass
属性を設定して次のいずれかのクラスを識別することで実行できます。
oracle.adf.controller.v2.PageController
クラスを拡張するクラス
oracle.adf.controller.v2.PagePhaseListener
インタフェースを実装するクラス
ページ定義のControllerClass
属性の値は次のいずれかになります。
完全修飾クラス名
前述の要件を満たすクラスに解決されるEL式
ControllerClass
の値にEL式を使用すると、faces-config.xml
ファイルでマネージドBeanとして構成したカスタム・ページ・コントローラ・クラス(またはページ・フェーズ・リスナー実装)の名前を指定できます。これにはJSFページのバッキングBeanが含まれます(PageController
が拡張されている場合またはPagePhaseListener
が実装されている場合)。
図10-13は、ページ定義のルート・ノードを構造ウィンドウで選択して設定する方法を示しています。
注意: ControllerClass 属性の値にEL式を使用すると、#{ YourExpr ession} が有効なクラスではないことを示す警告が構造ウィンドウに表示される場合があります。この警告は無視しても問題ありません。 |
SRDemoアプリケーションには、oracle.srdemo.view.util
パッケージのOnPageLoadBackingBeanBase
クラスが含まれています。このクラスにより、例10-2に示すようなコードを使用して、前述のPagePhaseListener
インタフェースが実装されます。通常のADFモデル準備フェーズの前にonPageLoad()
メソッドを起動し、通常のADFレンダリング準備フェーズの後にonPagePreRender()
メソッドを起動するために、このクラスでインタフェースのbeforePhase()
メソッドおよびafterPhase()
メソッドを実装します。
例10-2 PagePhaseListenerによるonPageLoad()メソッドおよびonPagePreRender()メソッドの起動
// In class oracle.srdemo.view.util.OnPageLoadBackingBeanBase /** * Before the ADF page lifecycle's prepareModel phase, invoke a * custom onPageLoad() method. Subclasses override the onPageLoad() * to do something interesting during this event. * @param event */ public void beforePhase(PagePhaseEvent event) { FacesPageLifecycleContext ctx = (FacesPageLifecycleContext)event.getLifecycleContext(); if (event.getPhaseId() == Lifecycle.PREPARE_MODEL_ID) { bc = ctx.getBindingContainer(); onPageLoad(); bc = null; } } /** * After the ADF page lifecycle's prepareRender phase, invoke a * custom onPagePreRender() method. Subclasses override the onPagePreRender() * to do something interesting during this event. * @param event */ public void afterPhase(PagePhaseEvent event) { FacesPageLifecycleContext ctx = (FacesPageLifecycleContext)event.getLifecycleContext(); if (event.getPhaseId() == Lifecycle.PREPARE_RENDER_ID) { bc = ctx.getBindingContainer(); onPagePreRender(); bc = null; } } public void onPageLoad() { // Subclasses can override this. } public void onPagePreRender() { // Subclasses can override this. }
マネージドBeanはこのインタフェースの実装をベース・クラスから継承するため、OnPageLoadBackingBeanBase
クラスを拡張するマネージドBeanであれば、ADFページ・フェーズ・リスナーとして使用できます。次に、そのバッキングBeanがonPageLoad()
とonPagePreRender()
の一方または両方のメソッドをオーバーライドする場合、そのメソッドは、ページ・リクエスト・ライフサイクル内の適切な時期にADFページ・ライフサイクルによって起動されます。このようなバッキングBeanを有効にするための最終手順では、バッキングBeanをそのページのページ・コントローラとして使用するようにADFページ定義に指示します。前述のとおり、この指示は、該当するページ定義のControllerClass
属性を、バッキングBeanに対して評価するEL式に設定して行います。
SRDemoアプリケーションのSRMain
ページでは、この項に記載された方法を使用して、oracle.srdemo.view.backing
パッケージのSRMain
バッキングBeanのonPageLoad()
メソッドにプログラム・コードを記述する方法を示しています。そのバッキングBeanの名前はfaces-config.xml
ではbacking_SRMain
であるため、SRMain
ページのページ定義のControllerClass
プロパティはEL式#{backing_SRMain}
に設定されます。
図10-14は、JSFページ・ライフサイクルと、ADFページ・ライフサイクルが追加する拡張ページ処理フェーズとの関係を示しています。Refresh
プロパティをページ定義内のイテレータ・バインディングおよびinvokeAction
実行可能ファイルで使用すると、ADFページ・ライフサイクル中にそれぞれが評価されるフェーズ(prepareModelフェーズもしくはprepareRenderフェーズ、またはその両方)を制御できます。リフレッシュという用語はわかりにくいため、この項では、実行可能ファイルのタイプごとにその意味を説明し、必要な動作を実現するためにRefresh
プロパティをどのように設定すればよいかについて説明します。
アプリケーション・モジュール内のビュー・オブジェクト・インスタンスのイテレータ・バインディングを操作するとき、実際にはデフォルト設定のRefresh="ifNeeded
"をそのまま使用できます。これをRefreshCondition
プロパティ内のブール値のEL式で補完すると、イテレータのリフレッシュを必要に応じて条件付きで回避できます。ここで、イテレータ・バインディングのリフレッシュの意味について説明します。
イテレータ・バインディングとは、その名前が示すとおり、イテレータをポイントするバインディングです。スケーラビリティ上の理由から、バインディング・コンテナ内のイテレータ・バインディングは、実行時に、行セット・イテレータへの参照を各リクエストの終了時に解放します。次のリクエスト中に、イテレータ・バインディングは、データ・コレクションの現在の行を追跡している有効な行セット・イテレータをポイントするように再度リフレッシュされます。ADFページ・ライフサイクル中のADFイテレータのリフレッシュとは、正確には、行セット・イテレータにアクセスし、バインディングをバインド先の行セット・イテレータに再結合する操作を意味します。
ライフサイクル中にリフレッシュされない場合、イテレータ・バインディングは、そのリクエストのどの行セット・イテレータもポイントしません。この結果、値バインディングは、表示するデータがないイテレータ・バインディングに関連付けられます。これは、最初はデータを表示しない検索ページのようなページなどの場合、望ましい結果となることがあります。これを実現するために、次のRefreshCondition
を使用できます。
#{adfFacesContext.postback == true}
adfFacesContext.postback
ブール型プロパティは、ページが最初にレンダリングされたとき、または別のページからの移動によりレンダリングされたときは、false
と評価されます。エンド・ユーザーがページ上のいずれかのUIコントロールと対話済の場合はtrue
と評価され、そのページへのポストバックが発生してイベントが処理されます。この式を特定のイテレータ・バインディングのRefreshCondition
として使用すると、ユーザーがページ上のコントロールと対話した場合にのみ、イテレータ・バインディングがリフレッシュされます。
イテレータ・バインディングのRefresh
プロパティの有効な値は次のとおりです。イテレータをリフレッシュするフェーズに応じて選択してください。
prepareModelとprepareRenderの両方のフェーズの場合は、Refresh="ifNeeded
"(デフォルト)を使用
prepareModelフェーズのみの場合は、Refresh="prepareModel
"を使用
prepareRenderフェーズのみの場合は、Refresh="renderModel
"を使用
独自のコードでイテレータ・バインディングにgetRowSetIterator()
をコールした場合にのみイテレータ・バインディングをリフレッシュする場合は、Refresh="never
"を設定します。その他のRefresh
の値は、イテレータ・バインディングには無関係であるか、将来使用するために予約されています。
アプリケーション・モジュールのビュー・オブジェクト・インスタンスに関連するイテレータ・バインディングを操作するときは、イテレータ・バインディングをリフレッシュしても、その問合せの再実行が毎回強制されるわけではないことを理解することが重要です。特定のユーザーの作業ユニット中にビュー・オブジェクト・インスタンスの行セット・イテレータへ最初にアクセスしたときは、ビュー・オブジェクトの問合せがまだ実行されていない場合、問合せが暗黙的に実行されます。同じ論理作業ユニットの一部であるページ・リクエストでそのビュー・オブジェクト・インスタンスに関連するイテレータ・バインディングをこの後でリフレッシュすると、行セット・イテレータへの再アクセスのみが行われ、問合せの再実行は強制されません。問合せを再実行してそのデータをリフレッシュするには、Execute
またはExecuteWithParams
という組込み操作を使用するか、イテレータ・バインディングでexecuteQuery()
メソッドをプログラムによってコールします。
SRDemoアプリケーションのいくつかのページ定義では、宣言的なinvokeAction
バインディングを使用して、この拡張ADFページ処理ライフサイクル中に、組込み操作またはカスタム操作をトリガーしています。各invokeAction
には、バインディングに名前を付けるid
プロパティの他に、主なプロパティが3つあります。
invokeAction
が起動した場合に行われる処理を制御するBinds
プロパティ
この値は、同じバインディング・コンテナにあるアクション・バインディングまたはメソッド・アクション・バインディングの名前になります。
invokeAction
によってアクション・バインディングが起動するフェーズを制御するRefresh
プロパティ
これを起動するには、ADFページ・ライフサイクルのフェーズに応じて次のいずれかを使用します。
prepareModelフェーズの場合は、Refresh=prepareModel
を使用
prepareRenderフェーズの場合は、Refresh=renderModel
を使用
prepareModelフェーズおよびprepareRenderフェーズの場合は、Refresh=ifNeeded
を使用
起動されるかどうかを制御できるRefreshCondition
プロパティ
この値を指定する場合は、ブール値のEL式になります。ページ・ライフサイクル中にinvokeAction
が考慮されたときに式がtrue
と評価されると、関連付けられているアクション・バインディングが起動します。false
と評価された場合、アクション・バインディングは起動しません。
注意: ここに記載されていないRefresh プロパティの他の値は、将来使用するために予約されています。 |
図10-14からわかるとおり、ADFのprepareModelフェーズとprepareRenderフェーズの主な違いは、一方がJSFのinvokeApplicationフェーズの前にあり、他方が後にあることです。JSFのinvokeApplicationフェーズではアクション・リスナーが起動されるため、これらのアクション・リスナーが自身の処理を実行した後にinvokeAction
をトリガーする必要がある場合は、Refresh="renderModel
"を設定します。
パラメータを受け入れるメソッド・アクション・バインディングにinvokeAction
がバインドされる場合は、prepareModelIfNeeded
およびrenderModelIfNeeded
の2つの追加の値をRefresh
プロパティに指定できます。これらの値は、*IfNeeded
接尾辞がない同等の設定と同じ意味を持ちますが、評価されたパラメータ値の現在のセットを、前回のメソッド・アクション・バインディングの起動に使用されたセットと比較するために最適化を実行する点が異なります。現在の起動に対するパラメータ値が前回使用した値と完全に同じ場合、invokeAction
は、バインドされているメソッド・アクション・バインディングを起動しません。
注意: Refresh プロパティのデフォルト値はifNeeded です。これは、起動を再調整するRefreshCondition 式を指定しない場合、各リクエスト中に、関連付けられているアクション・バインディングが2回起動されることを意味します。適切なRefreshCondition 式を追加するか(両方のフェーズ中に評価する場合)、JSFのinvokeApplication フェーズの前と後のどちらでinvokeAction を起動するかに応じて、invokeActionバインディングのデフォルトのRefresh設定をprepareModel またはrenderModel のいずれかに変更することをお薦めします。 |
getKey()
メソッドをどのビュー行でコールしても、行を識別する1つ以上のキー属性をカプセル化するKey
オブジェクトを取得できます。前述の例で説明したとおり、このようなKey
オブジェクトは、findByKey()
による行セット内のビュー行の検索にも使用できます。実行時に、setCurrentRowWithKey
またはsetCurrentRowWithKeyValue
という組込み操作のいずれかがデータ・バインディング・レイヤーによって名前別に起動されると、検索された行が現在の行として設定される前に、findByKey()
メソッドを使用して、パラメータとして渡された値に基づいて行が検索されます。
図10-15に示すように、setCurrentRowWithKey
操作およびsetCurrentRowWithKeyValue
操作はいずれもrowKey
という名前のパラメータを予想しますが、実行時にそのrowKey
パラメータに予想される値がそれぞれで異なるため、混乱が生じることがあります。
setCurrentRowWithKey
では、rowKey
パラメータ値がビュー行キーのシリアライズされた文字列表現であると予想されます。これは、次のような16進エンコード文字列です。
000200000002C20200000002C102000000010000010A5AB7DAD9
キーのシリアライズされた文字列表現により、ブラウザのURL文字列またはフォーム・パラメータで単一値として渡すことができる方法で、ビュー行のキーを構成する可能性のあるすべてのキー属性がエンコードされます。実行時に、有効なシリアライズされた文字列キーではないパラメータ値を不注意に渡すと、oracle.jbo.InvalidParamException
またはjava.io.EOFException
などの例外を結果として受信する場合があります。Webページでは、ADFコントロール・バインディングのrowKeyStr
プロパティ(#{bindings.SomeAttrName.rowKeyStr}
など)またはADF Faces表の行変数(#{row.rowKeyStr}
など)を参照すると、行のシリアライズされた文字列キーの値にアクセスできます。
setCurrentRowWithKeyValue
では、rowKey
パラメータ値がビュー行のキーを表すリテラル値であると予想します。たとえば、サービス・リクエスト番号201
を検索する場合、この値は単に201
になります。
注意: アプリケーション・モジュール・クラスにカスタム・コードを記述し、クライアントから渡されたシリアライズされた文字列キーに基づいて行を検索する必要がある場合は、oracle.jbo.client パッケージにあるJboUtil クラスのgetRowFromKey() メソッドを次のように使用できます。
static public Row getRowFromKey(RowSetIterator rsi, String sKey) 行を検索するビュー・オブジェクト・インスタンスを第1パラメータとして、キーのシリアライズされた文字列書式を第2パラメータとして渡します。 |
アプリケーション・モジュールに付属のバンドル例外モードという機能を使用すると、Webアプリケーションでは、発生した最初のエラーのみを提示するのではなく、失敗した検証例外の最大セットをエンド・ユーザーに簡単に提示できます。ADF Business Componentsアプリケーション・モジュール・プールでは、Webアプリケーションに対してバンドル例外モードをデフォルトで有効にしています。
このデフォルト設定は、通常変更する必要はありません。ただし、検証例外がスローされる方法に影響を与えることからデフォルトで有効になっていることを理解することが重要です。Java言語およびJavaランタイムは単一例外オブジェクトのスローのみをサポートするため、バンドルされた検証例外は、例外のセットを、それを含む新しい親例外の詳細としてラップすることで実装されます。たとえば、単一エンティティ・オブジェクトの複数の属性で属性レベルの検証ができない場合、これら複数のValidationException
オブジェクトは、RowValException
にラップされます。このラップ例外には、検証できなかった行の行キーが含まれています。トランザクションのコミット時に、コミット中に実行された検証を複数の行で渡せなかった場合、すべてのRowValException
オブジェクトは、包含するTxnValException
オブジェクトにラップされます。
カスタム・エラー処理コードを記述するときは、SRDemoアプリケーションのSRDemoPageLifecycle
クラスのオーバーライドされたreportErrors()
メソッドで示されるように、JboException
ベース例外クラスのgetDetails()
メソッドを使用すると、内部にバンドルされている例外を再帰的に処理できます。
注意: ここに記載されている例外クラスはすべて、oracle.jbo パッケージのクラスです。 |
この項では、SRDemoアプリケーションの各ページでSRService
アプリケーション・モジュールのビュー・オブジェクト・インスタンスおよびサービス・メソッドをどのように使用しているかを簡単に説明します。
図10-16は、SRList
ページのデータ・バインディングを示しています。
ServiceRequestsByStatus
ビュー・オブジェクト・インスタンスのServiceRequestsByStatusIterator
なし
ServiceRequestsByStatusIterator
イテレータ・バインディングに関連付けられているsetCurrentRowWithKey
、ExecuteWithParams
なし
なし
図10-17は、SRMain
ページのデータ・バインディングを示しています。
ServiceRequests
ビュー・オブジェクト・インスタンスのServiceRequestsIterator
ServiceHistories
ビュー・オブジェクト・インスタンスのServiceHistoriesIterator
なし
ServiceRequestsIterator
イテレータ・バインディングに関連付けられているsetCurrentRowWithKey
、Delete
ServiceHistoriesIterator
イテレータ・バインディングに関連付けられているCreate
、DeleteNewHistory
(Delete
組込みの場合)
SRService
データ・コントロールに関連付けられているCommit
deleteServiceHistoryNotes
がSRService
クライアント・インタフェース上のdeleteServiceHistoryNotes()
メソッドを起動
なし
注意: SRMain ページのSRMain バッキングBean(oracle.srdemo.view.backing パッケージ内)では、10.5.4.3項「カスタムADFページ・ライフサイクルによるonPageLoadバッキングBeanメソッドの起動」で説明されている方法を使用して、SREdit ページが宣言的に実行している処理と完全に同じ処理をプログラムで実行します。 |
ServiceRequests
は、エンティティ・ベースのビュー・オブジェクトServiceRequests
のインスタンスです。メインのServiceRequest
エンティティ・オブジェクトの慣用名および3つの追加の参照エンティティ・オブジェクトの慣用名、すなわちCreatedByUser
(User
エンティティ・オブジェクト)、AssignedToUser
(User
エンティティ・オブジェクト)およびProduct
からデータを結合します。ServiceRequests
ビュー・オブジェクトは、ServiceHistories
ビュー・オブジェクトにリンクされているマスター/ディテールです。
ServiceHistories
は、エンティティ・ベースのビュー・オブジェクトServiceHistories
のインスタンスです。メインのServiceHistory
エンティティ・オブジェクトの慣用名および1つの追加の参照エンティティ・オブジェクトの慣用名、すなわちSystemUser
(User
エンティティ・オブジェクト)からデータを結合します。これは、カスタムJavaクラスを持たない、XML専用のビュー・オブジェクトです。
例10-3に示すように、deleteServiceHistoryNotes()
メソッドにより、引数として渡されたキー・セット内のKey
オブジェクトに対応するサービス履歴メモ行が削除されます。
例10-3 SRServiceImpl.javaのDeleteServiceHistoryNotesメソッド
public void deleteServiceHistoryNotes(Set keySet) { if (keySet != null) { ViewObject histories = getServiceHistories(); for (Key k: (Set<Key>)keySet) { Row[] rowToDelete = histories.findByKey(k, 1); if (rowToDelete == null || rowToDelete.length == 0) { throw new JboException("Failed to find row with serialized key" + k.toStringFormat(false)); } rowToDelete[0].remove(); getDBTransaction().commit(); } } }
図10-18は、SREdit
ページのデータ・バインディングを示しています。
ServiceRequests
ビュー・オブジェクト・インスタンスのServiceRequestsIterator
ServiceRequestStatusList
ビュー・オブジェクト・インスタンスのServiceRequestStatusListIterator
なし
ServiceRequestsIterator
イテレータ・バインディングに関連付けられているsetCurrentRowWithKey
SRService
データ・コントロールに関連付けられているCommit
cancelEditsToCurrentServiceRequest
がSRService
クライアント・インタフェース上のcancelEditsToCurrentServiceRequest()
を起動
ページへの初回移動時(つまり、ポストバックを処理していない)で、かつ、processScope.rowKeyStr
属性が設定されていない(RefreshCondition="${adfFacesContext.postback == false and not empty processScope.rowKeyStr}
")場合、setRowToEditFromRequestParameter
が組込みsetCurrentRowWithKey
操作をモデル準備フェーズ中(Refresh="prepareModel
")に起動
ServiceRequests
は、エンティティ・ベースのビュー・オブジェクトServiceRequests
のインスタンスです。メインのServiceRequest
エンティティ・オブジェクトの慣用名および3つの追加の参照エンティティ・オブジェクトの慣用名、すなわちCreatedByUser
(User
エンティティ・オブジェクト)、AssignedToUser
(User
エンティティ・オブジェクト)およびProduct
からデータを結合します。
ServiceRequestStatusList
は、読取り専用ビュー・オブジェクトServiceRequestStatusList
のインスタンスです。そのデータは、ServiceRequestStatusListImpl.java
クラスにある静的リストから提供されます。このクラスは、静的データに基づくビュー・オブジェクトの実装に対する基本サポートを提供する、FrameworkExtensions
プロジェクトのSRStaticDataViewObjectImpl
を拡張します。
例10-4に示すように、cancelEditsToCurrentServiceRequest()
メソッドでは、refresh()
メソッドを使用して、現在のトランザクションで現在のサービス・リクエスト行に行われた編集内容を取り消します。
図10-19は、SRSearch
ページのデータ・バインディングを示しています。
SearchServiceRequests
ビュー・オブジェクト・インスタンスのSearchServiceRequestsIterator
(AlwaysFind
invokeActionによって検索モードに強制的に設定)
SearchServiceRequests
ビュー・オブジェクト・インスタンスのSearchServiceRequestsResultsIterator
ServiceRequestStatusList
ビュー・オブジェクト・インスタンスのServiceRequestStatusListIterator
なし
SearchServiceRequestsIterator
イテレータ・バインディングに関連付けられているExecute
、Delete
、Create
SearchServiceRequestsResultsIterator
イテレータ・バインディングに関連付けられているFind
、First
、Next
、Previous
、Last
、setCurrentRowWithKey
なし
SearchServiceRequestsIterator
が検索モードでない(${bindings.SearchServiceRequestsIterator.findMode == false}
)場合、AlwaysFind
が組込みFind
操作(SearchServiceRequestsIterator
イテレータ・バインディングの場合)をモデル準備フェーズまたはモデル・レンダリング・フェーズ中(Refresh="ifNeeded
")に起動
SearchServiceRequestsIterator
が検索モードでない(${bindings.SearchServiceRequestsIterator.findMode == false}
)場合、insertBlankViewCriteriaRowIfThereAreNone
が組込みCreate
操作をモデル準備フェーズまたはモデル・レンダリング・フェーズ中(Refresh="ifNeeded
")に起動
SearchServiceRequests
は、エンティティ・ベースのビュー・オブジェクトServiceRequests
のインスタンスです。メインのServiceRequest
エンティティ・オブジェクトの慣用名および3つの追加の参照エンティティ・オブジェクトの慣用名、すなわちCreatedByUser
(User
エンティティ・オブジェクト)、AssignedToUser
(User
エンティティ・オブジェクト)およびProduct
からデータを結合します。
ServiceRequestStatusList
は、読取り専用ビュー・オブジェクトServiceRequestStatusList
のインスタンスです。そのデータは、ServiceRequestStatusListImpl.java
クラスにある静的リストから提供されます。このクラスは、静的データに基づくビュー・オブジェクトの実装に対する基本サポートを提供する、FrameworkExtensions
プロジェクトのSRStaticDataViewObjectImpl
を拡張します。
なし
図10-20は、SRStaffSearch
ページのデータ・バインディングを示しています。
StaffListByEmailNameRole
ビュー・オブジェクト・インスタンスのStaffListByEmailNameRoleIterator
StaffListByEmailNameRole_Role
、StaffListByEmailNameRole_EmailAddress
、StaffListByEmailNameRole_TheFirstName
、StaffListByEmailNameRole_TheLastName
StaffListByEmailNameRoleIterator
イテレータ・バインディングに関連付けられているExecuteWithParams
なし
なし
図10-21は、SRManage
ページのデータ・バインディングを示しています。
StaffWithOpenRequests
ビュー・オブジェクト・インスタンスのStaffWithOpenRequestsIterator
ExpertiseAreas
ビュー・オブジェクト・インスタンスのExpertiseAreasIterator
OpenOrPendingServiceRequests
ビュー・オブジェクト・インスタンスのOpenOrPendingServiceRequestsIterator
ServiceHistoriesForRequest
ビュー・オブジェクト・インスタンスのServiceHistoriesForRequestIterator
なし
StaffWithOpenRequestsIterator
イテレータ・バインディングに関連付けられているsetCurrentStaffRowWithKey
(setCurrentRowWithKey
組込みの場合)
setCurrentProblemAndAssigneeRows
がSRService
クライアント・インタフェース上のsetCurrentProblemAndAssigneeRows()
を起動
なし
StaffWithOpenRequests
は、読取り専用ビュー・オブジェクトStaffWithOpenRequests
のインスタンスです。情報をUSERS
およびSERVICE_REQUESTS
表から問い合せます。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。このビュー・オブジェクトは、ExpertiseAreas
およびOpenOrPendingServiceRequests
ビュー・オブジェクトにリンクされているマスター/ディテールです。
ExpertiseAreas
は、エンティティ・ベースのビュー・オブジェクトExpertiseAreas
のインスタンスです。プライマリExpertiseArea
エンティティ・オブジェクトの慣用名および1つの参照Product
エンティティ・オブジェクトの慣用名から情報を結合します。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。
OpenOrPendingServiceRequests
は、読取り専用ビュー・オブジェクトOpenOrPendingServiceRequests
のインスタンスです。情報をSERVICE_REQUESTS
表から問い合せます。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。このビュー・オブジェクトは、ServiceHistories
ビュー・オブジェクトにリンクされているマスター/ディテールです。
ServiceHistoriesForRequest
は、エンティティ・ベースのビュー・オブジェクトServiceHistories
のインスタンスです。メインのServiceHistory
エンティティ・オブジェクトの慣用名および1つの追加の参照エンティティ・オブジェクトの慣用名、すなわちSystemUser
(User
エンティティ・オブジェクト)からデータを結合します。これは、カスタムJavaクラスを持たない、XML専用のビュー・オブジェクトです。
例10-5に示すように、setCurrentProblemAndAssigneeRows()
メソッドでは、ヘルパー・メソッドを使用して、渡されたシリアライズされた文字列キーに基づき、StaffWithOpenRequests
ビュー・オブジェクト・インスタンスおよびOpenOrPendingServiceRequests
ビュー・オブジェクト・インスタンスに現在の行を設定します。
図10-22は、SRSkills
ページのデータ・バインディングを示しています。
StaffList
ビュー・オブジェクト・インスタンスのStaffListIterator
StaffExpertiseAreas
ビュー・オブジェクト・インスタンスのStaffExpertiseAreasIterator
ProductList
ビュー・オブジェクト・インスタンスのProductListIterator
なし
なし
updateSkillsForCurrentStaff
がSRService
クライアント・インタフェース上のupdateSkillsForCurrentStaff()
メソッドを起動
なし
StaffList
は、エンティティ・ベースのビュー・オブジェクトStaffList
のインスタンスです。プライマリ・エンティティ・オブジェクトの慣用名SystemUser
(User
エンティティ・オブジェクト)から情報を問い合せます。このビュー・オブジェクトは、ExpertiseAreas
ビュー・オブジェクトにリンクされているマスター/ディテールです。
StaffExpertiseAreas
は、エンティティ・ベースのビュー・オブジェクトExpertiseAreas
のインスタンスです。プライマリExpertiseArea
エンティティ・オブジェクトの慣用名および1つの参照Product
エンティティ・オブジェクトの慣用名から情報を結合します。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。
ProductList
は、エンティティ・ベースのビュー・オブジェクトProductList
のインスタンスです。プライマリ・エンティティ・オブジェクトの慣用名Products
(Product
エンティティ・オブジェクト)からデータを問い合せます。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。
例10-6に示すように、updateSkillsForCurrentStaff()
メソッドでは、次の手順を実行します。
製品IDのリストをクローニングします。
ExpertiseAreas
の反復処理をプログラムで行うセカンダリRowSetIterator
を作成します。
製品IDのリストにない製品の現在のユーザーの行を削除します。
反復処理の実行時に2次行セット・イテレータをクローズします。
残っているキー用に新規行を追加します。
トランザクションをコミットします。
例10-6 SRServiceImpl.javaのUpdateSkillsForCurrentStaffメソッド
public void updateSkillsForCurrentStaff(List productIds) { if (productIds != null && productIds.size() > 0) { // 1. Cone the list of product ids List<Number> copyOfProductIds = (List<Number>)Utils.cloneList(productIds); ViewObject skills = getStaffExpertiseAreas(); // 2. Create a secondary rowset iterator for iteration RowSetIterator rsi = skills.createRowSetIterator(null); // 3. Remove rows for current user for products not in list of products while (rsi.hasNext()) { Row r = rsi.next(); Number productId = (Number)r.getAttribute("ProdId"); // if the existing row is in the list, we're ok, so remove from list. if (copyOfProductIds.contains(productId)) { copyOfProductIds.remove(productId); } // if the existing row is in not list, remove it. else { r.remove(); } } // 4. Close the secondary row set iterator when we're done rsi.closeRowSetIterator(); // 5. Add new rows for the keys that are left for (Number productIdToAdd: copyOfProductIds) { Row newRow = skills.createRow(); skills.insertRow(newRow); newRow.setAttribute("ProdId", productIdToAdd); } // 6. Commit the transaction getDBTransaction().commit(); } }
注意: ADF Modelレイヤーのイテレータ・バインディングでは、関連付けられているビュー・オブジェクト・インスタンスのデフォルト行セットのデフォルト行セット・イテレータへのバインドをデフォルトで行うため、ビュー・オブジェクトの行セットの反復処理をプログラムで実行する2次行セット・イテレータをアプリケーション・ビジネス・ロジックに作成することをお薦めします。この方法では、ユーザー・インタフェースでユーザーに表示される現在の行が影響を受けません。2次イテレータには開発者が名前を割り当てることができますが、null を渡すと、名前が自動的に割り当てられます。通常は、反復処理の終了と同時にこのイテレータをクローズするため、名前を手動で割り当てる必要は特にありません。 |
図10-23は、SRCreate
ページのデータ・バインディングを示しています。
Globals
ビュー・オブジェクト・インスタンスのGlobalsIterator
ProductList
ビュー・オブジェクト・インスタンスのProductListIterator
なし
なし
cancelNewServiceRequest
がSRService
クライアント・インタフェース上のcancelNewServiceRequest
メソッドを起動
ページでポストバック・イベントを処理していない場合で、かつ、requestScope.processChoice
属性が設定されていない(RefreshCondition="${adfFacesContext.postback == false and empty requestScope.processChoice}
")場合、clearServiceRequestFieldsIfNotInTrain
がcancelNewServiceRequest
メソッド・アクション・バインディングをモデル準備フェーズ中(Refresh="prepareModel
")に起動
ProductList
は、エンティティ・ベースのビュー・オブジェクトProductList
のインスタンスです。プライマリ・エンティティ・オブジェクトの慣用名Products
(Product
エンティティ・オブジェクト)からデータを問い合せます。これは、Javaクラスが関連付けられていない、XML専用のビュー・オブジェクトです。
Globals
は、一時ビュー・オブジェクトGlobals
のインスタンスです。ページ全体のProductId
、ProductName
およびProductDescription
に関する情報を一時的に格納する一時属性を含んでいます。
注意: 一時ビュー・オブジェクトは、SQL問合せを持たない、一時属性のみのオブジェクトです。このオブジェクトには、アプリケーション・モジュールのビジネス・ロジックによってプログラムで移入される行、またはADF Modelレイヤーの組込み操作のアクション・バインディングを使用して宣言的に移入される行を含めることができます。Oracle Formsを使い慣れているユーザーは、これをFormsの非データベース・ブロックに類似したものと考えることができます。 |
例10-7に示すように、cancelNewServiceRequest()
メソッドにより、Globals
ビュー・オブジェクト・インスタンスに単一の空白行が用意されます。
図10-24は、SRConfirmCreate
ページのデータ・バインディングを示しています。
Globals
ビュー・オブジェクト・インスタンスのGlobalsIterator
LoggedInUser
ビュー・オブジェクト・インスタンスのLoggedInUserIterator
なし
なし
cancelNewServiceRequest
がSRService
クライアント・インタフェース上のcancelNewServiceRequest()
を起動
createServiceRequest
がSRService
クライアント・インタフェース上のcreateServiceRequest()
を起動
なし
Globals
は、一時ビュー・オブジェクトGlobals
のインスタンスです。ページ全体のProductId
、ProductName
およびProductDescription
に関する情報を一時的に格納する一時属性を含んでいます。
LoggedInUser
は、エンティティ・ベースのビュー・オブジェクトLoggedInUser
のインスタンスです。プライマリ・エンティティ・オブジェクトの慣用名Users
(User
エンティティ・オブジェクト)からデータを問い合せます。LoggedInUser
ビュー・オブジェクトは、ServiceRequestsByStatus
ビュー・オブジェクトにリンクされているマスター/ディテールです。
例10-8に示すように、createServiceRequest()
メソッドでは、次の基本手順を実行します。
ServiceRequest
のエンティティ定義を取得します。
新規ServiceRequest
エンティティ行(ServiceRequestImpl
クラス)を作成します。
Globals
の現在の行に強く型付けされたGlobalsRowImpl
としてアクセスします。
新しいサービス・リクエストの問題の説明と製品IDを設定します。
トランザクションをコミットします。
データベース・トリガーによって割り当てられた新しいサービス・リクエストのSR番号を表す整数を戻り値として提供します。
例10-8 SRServiceImpl.javaのCreateServiceRequestメソッド
public Integer createServiceRequest() { // 1. Get the entity definition for ServiceRequest EntityDefImpl svcReqDef = ServiceRequestImpl.getDefinitionObject(); // 2. Create a new ServiceRequest entity row ServiceRequestImpl newReq = (ServiceRequestImpl)svcReqDef.createInstance2(getDBTransaction(),null); // 3. Access the current row in Globals as a strongly-typed GlobalsRowImpl GlobalsRowImpl globalsRow = (GlobalsRowImpl)getGlobals().getCurrentRow(); // 4. Set the problem description and product id for new service request newReq.setProblemDescription(globalsRow.getProblemDescription()); newReq.setProdId(globalsRow.getProductId()); // 5. Commit the transaction getDBTransaction().commit(); // 6. Return an integer representing the database-assigned SR Number return newReq.getSvrId().getSequenceNumber().intValue(); }