ヘッダーをスキップ
Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド
11gリリース1 (11.1.1.7.0)
B52028-05
  目次へ移動
目次

前
 
次
 

6 ビュー・オブジェクト問合せ結果の操作

この章では、JDeveloperで提供されるビジネス・コンポーネント・ブラウザを使用してADFビュー・オブジェクト問合せ結果を対話的にテストする方法について説明します。この章では、ビジネス・コンポーネントAPIを使用してJDeveloper外部のテスト・クライアントに含まれるビュー・オブジェクト・インスタンスにアクセスする方法についても説明します。

この章の内容は次のとおりです。

6.1 ビュー・オブジェクトの実行時動作の概要

JDeveloperには、アプリケーション・ユーザー・インタフェースを使用せず、またはテスト・クライアントのプログラムを記述せずに、データ・モデルのすべての面をテストできるようにする、対話型アプリケーション・モジュール・テスト・ツールが用意されています。ビジネス・コンポーネント・ブラウザの実行は一般的には、開発時にビジネス・サービスのデータ機能を実行する最も迅速な方法です。


注意:

アプリケーション・モジュールをプログラムによってテストする場合は、テスト・クライアントを記述できます。詳細は、6.4.2項「コマンドラインJavaテスト・クライアントの作成方法」を参照してください。問合せの実行をログに出力する場合は、ADFロガーを使用してください。詳細は、31.5項「ADFロガーの使用」を参照してください。


ビジネス・コンポーネント・ブラウザを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーによるアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成したでも、ビジネス・コンポーネント・ブラウザは問題が発生した場合の診断に役立ちます。ビジネス・コンポーネント・ブラウザで問題を再現して、問題がアプリケーションのビューまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。

6.2 ビュー・インスタンスをテストするためのアプリケーション・モジュールの作成

データ・モデル・プロジェクトで作成したビュー・オブジェクトをテストするには、テスト対象のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成する必要があります。アプリケーション・モジュールは、ビジネス・コンポーネント・ブラウザ(またはUIクライアント)がアプリケーション・データの操作に使用するトランザクション・コンポーネントです。アプリケーション・モジュールで使用される一連のビュー・オブジェクトは、それ自体のデータ・モデル、つまり、クライアントがユーザー・インタフェースを介して表示および操作できる一連のデータを定義します。

アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるビジネス・コンポーネント・ブラウザを使用します。ビジネス・コンポーネント・ブラウザの使用の詳細は、6.3項「ビジネス・コンポーネント・ブラウザを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。

6.2.1 個別のビュー・オブジェクト・インスタンスを使用したアプリケーション・モジュールの作成方法

個別のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成するには、「新規ギャラリ」から使用できる「アプリケーション・モジュールの作成」ウィザードを使用します。

作業を始める前に、次のようにします。

5.2.1項「エンティティ・ベースのビュー・オブジェクトの作成方法」および5.2.3項「エキスパート・モードの読取り専用ビュー・オブジェクトの作成方法」の説明に従って、目的のビュー・オブジェクトを作成します。

個別のビュー・オブジェクト・インスタンスをテストするためのアプリケーション・モジュールを作成するには:

  1. アプリケーション・ナビゲータで、アプリケーション・モジュールを作成するプロジェクトを右クリックし、「新規」を選択します。

  2. 「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」「アプリケーション・モジュール」の順に選択して、「OK」をクリックします。

  3. 「項目」リストで、「アプリケーション・モジュール」を選択し、アプリケーション・モジュールの作成ウィザードを起動します。

  4. アプリケーション・モジュールの作成ウィザードの「名前」ページで、パッケージ名およびアプリケーション・モジュール名を指定します。「次へ」をクリックします。

  5. 「データ・モデル」ページで、以前に定義したビュー・オブジェクトのインスタンスを指定し、このビュー・オブジェクト・インスタンスの名前をクライアントで認識される名前とまったく同じ名前に編集します。次に、「終了」をクリックします。

    「データ・モデル」ページに表示されるデフォルトのインスタンス名を受け入れるかわりに、インスタンス名をわかりやすい名前に変更できます(たとえば、デフォルト名OrderItems1のかわりに、AllOrderItemsに名前を変更できます)。

6.2.2 マスター/ディテール・ビュー・オブジェクト・インスタンスを使用したアプリケーション・モジュールの作成方法

アプリケーション・モジュールの作成ウィザードを使用して、ビュー・オブジェクトが表すマスター/ディテール関連に基づいてアプリケーション・モジュールのビュー・オブジェクトの階層を作成することもできます。

作業を始める前に、次のようにします。

5.6項「マスター/ディテール階層における複数表の使用」の説明に従って、ビュー・オブジェクト間の階層関係を作成します。

ビュー・オブジェクト関連に基づいてアプリケーション・モジュールを作成するには:

  1. アプリケーション・ナビゲータで、アプリケーション・モジュールを作成するプロジェクトを右クリックし、「新規」を選択します。

  2. 「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」「アプリケーション・モジュール」の順に選択して、「OK」をクリックします。

  3. 「項目」リストで、「アプリケーション・モジュール」を選択し、アプリケーション・モジュールの作成ウィザードを起動します。

  4. アプリケーション・モジュールの作成ウィザードで、「データ・モデル」ノードを選択します。

  5. 左側の「選択可能なビュー・オブジェクト」リストで、アクティブに調整するマスターにする必要があるビュー・オブジェクトのインスタンスを選択します。

    リスト内のマスター・ビュー・オブジェクトには、このビュー・オブジェクトにビュー・リンクがあることを示すプラス記号が表示されます。ビュー・リンクは、マスター/ディテール階層の定義に必要です。

    たとえば、図6-1は、選択したPersonsVOと、「新規ビュー・インスタンス」フィールドで名前を変更したAuthenticatedUserを示しています。

    図6-1 選択したマスター・ビュー・オブジェクト

    アプリケーション・モジュールの作成ウィザードの「データ・モデル」ページ
  6. 選択したマスター・ビュー・オブジェクトを「データ・モデル」リストに移動します。

    たとえば、図6-2は、「データ・モデル」リストに追加した後の新規作成したマスター・ビュー・インスタンスAuthenticatedUserを示しています。

    図6-2 作成したマスター・ビュー・インスタンス

    アプリケーション・モジュールの作成ウィザードの「データ・モデル」ページ
  7. 「データ・モデル」リストで、新規作成したマスター・ビュー・インスタンスを選択して強調表示しておきます。これは、追加するディテール・ビュー・インスタンスのターゲットになります。次に、「選択可能なビュー・オブジェクト」リストで、マスター・ビュー・オブジェクトの下のディテール・ビュー・オブジェクトを特定して選択します。

    たとえば、図6-3は、マスター・ビュー・オブジェクトPersonsVOの下にある、OrdersVO via PersonsToOrdersという名前のディテール・ビュー・オブジェクトOrdersVOを示しています。この名前はビュー・リンクPersonsToOrdersを表し、PersonsVOOrdersVO間のマスター/ディテール階層を定義します。ディテール・ビュー・インスタンスの名前はMyOrdersに変更されます。

    図6-3 選択したディテール・ビュー・オブジェクト

    アプリケーション・モジュールの作成ウィザードの「データ・モデル」ページ
  8. 追加したマスター・インスタンスにディテール・インスタンスを追加するには、「データ・モデル」リストで選択したマスター・ビュー・インスタンスの下に、ディテール・ビュー・オブジェクトを移動します。

    図6-4は、データ・モデルにAuthenticatedUserのディテールとして新規作成したディテール・ビュー・インスタンスMyOrdersを示しています。

    図6-4 作成したマスター・ビュー・インスタンス

    アプリケーション・モジュールの作成ウィザードの「データ・モデル」ページ
  9. 別の階層レベルを追加するには、新しく追加したディテール・インスタンスを「データ・モデル」リストで選択してから、新しいディテール・インスタンスを移動します。このディテール・インスタンスは、前に追加したディテール・インスタンスとマスター/ディテール関係を持ちます。

    データ・モデルには、ビュー・オブジェクト関係でサポートされているだけの数の階層レベルを含めることができます。たとえば、図6-5には、「データ・モデル」リストに、インスタンスAuthenticatedUser(PersonsVOから名前を変更)がMyOrders(OrdersVO via PersonsToOrdersから名前を変更)のマスターとして、またこれがMyOrderItems(OrderItemsVO via OrdersToOrderItemsから名前を変更)のマスターとして表示されています。ディテール・ビュー・オブジェクトのMyOrderItemsは、別のビュー・オブジェクトのマスターではないため、階層の最後のレベルになります。

    図6-5 作成したマスター/ディテール/ディテール階層

    ビジネス・コンポーネント・ブラウザの「データ・モデル」ページ

6.3ビジネス・コンポーネント・ブラウザを使用したビュー・オブジェクト・インスタンスのテスト

ビジネス・コンポーネント・ブラウザを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーによるアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成したでも、ビジネス・コンポーネント・ブラウザは問題が発生した場合の診断に役立ちます。ビジネス・コンポーネント・ブラウザで問題を再現して、問題がアプリケーションのビューまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。

6.3.1ビジネス・コンポーネント・ブラウザの実行方法

アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるビジネス・コンポーネント・ブラウザを使用します。

アプリケーション・モジュール構成でビュー・オブジェクトをテストするには:

  1. アプリケーション・ナビゲータで、目的のアプリケーション・モジュールおよびビュー・オブジェクトを含むプロジェクトを展開します。

  2. アプリケーション・モジュールを右クリックし、「実行」を選択します。

    または、デバッグを有効にしたビジネス・コンポーネント・ブラウザでアプリケーションを実行する場合は「デバッグ」を選択します。JDeveloperにより、ログ・ウィンドウのデバッガ・プロセス・パネルおよび各種デバッガ・ウィンドウが開きます。たとえば、ビジネス・コンポーネント・ブラウザを使用してデバッグする場合、ステータス・メッセージと例外を表示し、ソース・コードをステップ・インおよびステップ・アウトし、ブレークポイントを管理できます。

    ADFビジネス・コンポーネントのデバッグに特有の診断メッセージを受信する方法の詳細は、6.3.8項「ADFビジネス・コンポーネント・デバッグ診断を有効化する方法」を参照してください。

  3. 「ビジネス・コンポーネント構成の選択」ダイアログで、「ビジネス・コンポーネントの構成名」リストから目的のアプリケーション・モジュール構成を選択し、ビジネス・コンポーネント・ブラウザを実行します。

    デフォルトでは、アプリケーション・モジュールには、AppModuleNameLocalおよびAppModuleNameSharedという名前のデフォルトの構成のみがあります。たとえば、図6-6は、データベースに接続するアプリケーション・モジュールで使用するStoreFrontModuleLocal構成を示しています。

    アプリケーション・モジュール用として別の追加構成を作成してある場合、かわりにこれらの1つを使用してアプリケーション・モジュールをテストするには、「接続」をクリックする前に、「構成」ダイアログの「ビジネス・コンポーネントの構成名」ドロップダウン・リストから目的の構成を選択します。

    図6-6 「構成」ダイアログでの構成の選択

    ビジネス・コンポーネント・ブラウザの「構成」ダイアログ
  4. 「接続」をクリックし、選択した構成を使用してアプリケーション・モジュールを起動します。

  5. ビジネス・コンポーネント・ブラウザでビュー・オブジェクトを実行するには、データ・モデルのツリーを展開し、目的のビュー・オブジェクト・ノードをダブルクリックします。

    ビュー・オブジェクト・インスタンスはすでにテスト・セッションで実行されているように表示される場合があります。この場合、ビジネス・コンポーネント・ブラウザの右側のデータ・ビュー・ページには、すでにビュー・オブジェクト・インスタンスの問合せ結果が表示されています。読取り専用ビュー・オブジェクトのビジネス・コンポーネント・ブラウザ・データ・ビュー・ページのフィールドは、そのビュー・オブジェクトで表されるデータが編集できないため、常に無効として表示されます。たとえば、図6-7では、ビュー・インスタンスProductsのデータがブラウザに表示されています。「製品ID」「言語」「カテゴリ」などのフィールドは、属性を編集できないため、無効として表示されます。

    図6-7 ビジネス・コンポーネント・ブラウザでのデータ・モデルのテスト

    データ・モデルをテストする場合のビジネス・コンポーネント・ブラウザ
  6. ビジネス・コンポーネント・ブラウザの左側にあるデータ・モデル・ツリーのノードを右クリックし、そのノードのポップアップ・メニューを表示します。たとえば、ビュー・オブジェクト・ノードでは、データ・モデル・ツリーからのビュー・オブジェクトの削除、およびその他のタスクの実行のため、必要に応じて問合せを再実行できます。

  7. タブのポップアップ・メニューを表示するには、図6-8で示すように、開いているデータ・ビューアのタブを右クリックします。たとえば、データ・ビューアを閉じたり、別のウィンドウで開くことができます。

    図6-8 ビジネス・コンポーネント・ブラウザでのデータ・ビューアのタブのポップアップ・メニュー

    ビジネス・コンポーネント・ブラウザのポップアップ・メニュー

6.3.2 エンティティ・ベースのビュー・オブジェクトの対話的テスト方法

エンティティ・ベースのビュー・オブジェクトの対話的テストは、読取り専用ビュー・オブジェクトと同じ方法で行います。目的のビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加してから、ビジネス・コンポーネント・ブラウザを使用してこのアプリケーション・モジュールをテストします。

ビジネス・コンポーネント・ブラウザは、アプリケーション・モジュールを簡単にテストおよびデバッグできる非常に便利なツールです。表6-1に、エンティティ・ベースのビュー・オブジェクトを表示する際にビジネス・コンポーネント・ブラウザのツールバー・ボタンで実行する操作の概要を示します。

表6-1 ビジネス・コンポーネント・ブラウザのツールバー・ボタン

ボタン 操作 使用方法

ナビゲーション・ボタン


別の行に移動

ビジネス・コンポーネント・ブラウザによって表示される現在の行を変更します。最初、前、次、または最後の行に移動します。

「行の挿入」ボタン


新規行を挿入

新規の行を作成して挿入します。

「行の削除」ボタン


現在の行を削除

現在の行を削除します。

「変更の保存」ボタン


データベースへの変更を保存

ADFビジネス・コンポーネント・キャッシュに加えた変更をポストしてコミットします。

「変更の取消」ボタン


前回の保存以降の変更をすべて取消し

ADFビジネス・コンポーネント・キャッシュで加えた変更を破棄して元の値に戻し、データベースにポストされたすべての変更をロールバックします。

「ビュー基準の指定」ボタン


ビュー基準の指定

ビジネス・コンポーネントの「ビュー基準」ダイアログが表示され、ビュー基準を作成し、マスター・ビュー・オブジェクト・インスタンスに適用できます。

「行の検証」ボタン


行の検証

すべてのエンティティ・オブジェクト・インスタンスに対して定義済の検証規則を適用し、現在の行を検証します。最低1つのフィールドが編集可能でないと、使用できません。

「バインド変数の編集」ボタン


バインド変数の編集

「バインド変数」ダイアログが表示され、ビュー・オブジェクト問合せで使用されるバインド・パラメータの値を入力できます。問合せ文のビュー・オブジェクト問合せでバインド・パラメータが使用されていないと、使用できません。


アプリケーション・モジュールに追加したエンティティ・ベースのビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるビジネス・コンポーネント・ブラウザを使用します。

アプリケーション・モジュール構成を使用してエンティティ・ベースのビュー・オブジェクトをテストするには:

  1. アプリケーション・ナビゲータでアプリケーション・モジュールを選択し、ポップアップ・メニューから「実行」を選択します。

  2. 「ビジネス・コンポーネント・ブラウザ構成の選択」ダイアログで「接続」をクリックし、テスト用の目的の構成を使用します。

  3. ビジネス・コンポーネント・ブラウザでエンティティ・ベースのビュー・オブジェクトを実行するには、データ・モデルのツリーを展開し、目的のビュー・オブジェクト・ノードをダブルクリックします。

    読取り専用ビュー・オブジェクトと異なり、データ・ビュー・ページに表示されるフィールドは、そのビュー・オブジェクトで表されるデータを編集できるため、有効として表示されます。

  4. 編集可能なフィールドでは、個々の値の更新と入力したデータの検証チェックを実行できます。

    参照されるエンティティを持つビュー・インスタンスの場合は、外部キー値を変更して、参照部分の変更を確認できます。

  5. ツールバー・ボタンを使用すると、行の移動、作成、削除、および現在の行の検証など、行レベルの操作が可能です。

    エンド・ユーザーによるデータ・ビュー・ページ操作のシミュレーションの詳細は、6.3.5項「ビジネス・コンポーネント・ブラウザでのエンド・ユーザーによる対話のシミュレーション方法」を参照してください。

6.3.3 プロジェクトの変更を表示するようにビジネス・コンポーネント・ブラウザを更新する方法

通常の場合、データ・モデル・プロジェクトに対して行う変更は、ビジネス・コンポーネント・ブラウザを実行しても自動的に取得されません。しかし、表示されるデータ・モデルとデータ・モデル・プロジェクトの同期を取る必要があるときはいつでも、ビジネス・コンポーネント・ブラウザがデータ・モデル・プロジェクトからメタデータをリロードするように設定できます。このオプションは、ビジネス・コンポーネント・ブラウザの終了、プロジェクトの編集、およびビジネス・コンポーネント・ブラウザの再起動という最新の変更を表示するための一連の手順の代替手段です。

「アプリケーションのリロード」オプションを使用すると、特にビジネス・コンポーネント・ブラウザとJDeveloperを繰り返し切替えて作業する場合に時間を節約できます。たとえば、ビジネス・コンポーネント・ブラウザの実行中に、データ・モデルを新しいビュー・インスタンスを使用してデータ・モデルを変更する必要が生じたり、ビュー・インスタンスにLOV属性定義が足りないことが判明したりすることがあります。JDeveloperに戻り、ビジネス・コンポーネントの概要エディタを使用して変更操作を行い、データ・モデルのメタデータを変更します。次に、プロジェクトを再コンパイルした後(必須の手順)、ビジネス・コンポーネント・ブラウザに戻って、プロジェクトのクラス・パスから更新済のメタデータをリロードできます。

実行中のビジネス・コンポーネント・ブラウザでデータ・モデルのメタデータをリロードするには:

  1. アプリケーション・ナビゲータで、目的アプリケーション・モジュールを右クリックして、「実行」を選択します。

  2. データ・モデルをテストし、行う変更を決定します。ビジネス・コンポーネント・ブラウザは終了しないでください。

  3. JDeveloperで、目的の変更を行い、データ・モデル・プロジェクトを再コンパイルします(たとえば、「アプリケーション・ナビゲータ」で、データ・モデル・プロジェクトを右クリックし、「メイク」を選択して再コンパイル手順を完了します)。

    メタデータに対して行う変更とプロジェクトのコンパイルに関連性はありませんが、メタデータをクラス・パスにコピーし、ビジネス・コンポーネント・ブラウザによってリロードできるようにするには、コンパイル手順を実行する必要があります。

  4. ビジネス・コンポーネント・ブラウザに戻り、データ・モデル・ツリーの上の「アプリケーション・メタデータのリロード」ボタンをクリックします。ビジネス・コンポーネント・ブラウザが、開いているすべてのウィンドウを閉じます。

    または、ビジネス・コンポーネント・ブラウザの「ファイル」メニューから、アプリケーションのリロードを選択できます。

  5. 目的のウィンドウを再度開き、行った変更を表示します。

6.3.4ビジネス・コンポーネント・ブラウザ使用時の処理

ビジネス・コンポーネント・ブラウザを起動する場合、JDeveloperでは別のプロセスでツールが起動され、ビジネス・コンポーネント・ブラウザが表示されます。ダイアログの左側のツリーには、アプリケーション・モジュールのデータ・モデルのすべてのビュー・オブジェクト・インスタンスが表示されます。目的のビュー・オブジェクト・インスタンスをダブルクリックすると、問合せ結果を検査するデータ・ビュー・ページがビジネス・コンポーネント・ブラウザに表示されます。たとえば、図6-7は、展開されたツリーでビュー・インスタンスProductsをダブルクリックし、右側のデータ・ビュー・ページにこのビュー・インスタンスのデータが表示された様子を示しています。

データは編集できないため、表示する読取り専用のビュー・オブジェクトすべてに対して、データ・ビュー・ページは無効になっています。ただし、読取り専用のビュー・オブジェクトの場合でも、ツールはいくつかの有用な機能を備えています。

  • 「ラベル・テキスト」のコントロール・ヒントに基づいたUIヒント、およびフォーマット・マスクが正しく定義されているかどうかを検証できます。

  • ツールバー・ボタンを使用してデータのスクロールもできます。

  • Query-By-Example基準を入力して、検査対象のデータのある特定の行を検索できます。ツールバーの「ビュー基準の指定」ボタンをクリックすると、「ビュー基準」ダイアログに使用可能なQuery-by-Example基準のリストが表示されます。

    たとえば、図6-9に示すように、CustomerInfoVOCriteriaなどのビュー基準を選択し、LastName属性にH%などの問合せ基準を入力して、「検索」をクリックすると、検索対象を文字Hで始まる姓のユーザーのみに絞り込むことができます。

6.3.2項「エンティティ・ベースのビュー・オブジェクトの対話的テスト方法」で説明しているように、行の挿入、更新および削除をシミュレートできるエンティティ・ベースのビュー・オブジェクトを作成する場合、ビジネス・コンポーネント・ブラウザのほうが便利です。

図6-9 組込みQuery-By-Example機能

「ビジネス・コンポーネント・ビュー基準」ダイアログ

6.3.5ビジネス・コンポーネント・ブラウザでのエンド・ユーザーによる対話のシミュレーション方法

ビジネス・コンポーネント・ブラウザを起動すると、アプリケーション・モジュールのデータ・モデルで定義されているビュー・オブジェクト・インスタンスの階層が左側のツリーに表示されます。データ・モデルにマスター/ディテールのビュー・インスタンス関係が定義されている場合、ツリーには親ノードと子コードとして関係が表示されます。マスター/ディテールのビュー・インスタンス間のノードは、マスターで現在の行が変更されたときにマスター/ディテールをアクティブに調整するビュー・リンク・インスタンスを示します。たとえば、図6-10では、ツリーが展開され、マスター・ビュー・インスタンスProductByCategory1とディテール・ビュー・インスタンスProductStockLevelsByLocation1のマスター/ディテール関係が示されています。選択されているノードのProductWarehousesLevelsLink1は、マスター/ディテール関係が定義されているビュー・リンク・インスタンスです。

図6-10 ビジネス・コンポーネント・ブラウザでのアプリケーション・モジュールのデータ・モデル

ビジネス・コンポーネント・ブラウザのデータ・モデル

ビュー・リンク・インスタンスをダブルクリックすると、マスター・オブジェクトが実行され、データ・ビュー・ページにマスター/ディテール・データが表示されます。たとえば、図6-11では、ツリーのProductWarehousesLevelsLink1ビュー・リンク・インスタンスをダブルクリックすると、データ・ビュー・ページの上部のProductsByCategoryマスター・ビュー・インスタンスが実行され、データ・ビュー・ページの下部のProductStockLevelsByLocation1ビュー・インスタンスが実行されます。ビュー・オブジェクト・ノード上に表示される追加ポップアップ・メニュー項目では、データ・モデル・パネルからのビュー・オブジェクトの削除、およびその他のタスクの実行のため、必要に応じて問合せを再実行できます。

マスター/ディテール・データ・ビュー・ページでは、問合せ結果をスクロールできます。また、エンティティ・ベースのビュー・オブジェクトのインスタンスは完全に編集可能なため、読取り専用ビュー・オブジェクトの読取り専用のデータを表示している無効な UIコントロールを表示するかわりに、データ・ビュー・ページには編集可能なフィールドが表示されます。作成、挿入、更新、検証、コミットおよびロールバックを自由に試すことができます。

図6-11 ビジネス・コンポーネント・ブラウザのマスター/ディテール・データ・ビュー・ページ

編集可能なエンティティ・ベースのビュー・オブジェクトが表示されたブラウザ

たとえば、複数のデータ・ビュー・ページを同時に開いて、マスター/ディテール階層の複数レベルを表示できます。「連結解除」ポップアップ・メニュー項目を使用して、任意のタブを別のウィンドウで開き、複数のビュー・オブジェクトのデータを同時に視覚化します。

マスター/ディテール・データ・ビュー・ページを使用して、アプリケーションの様々な機能領域をテストできます。

6.3.5.1 マスター/ディテール調整のテスト

ビジネス・コンポーネント・ブラウザのツールバーのナビゲーション・ボタンをクリックすると、現在のマスター・ビュー・オブジェクトの行が正しく調整されているかどうかを確認できます。たとえば、図6-11は、製品と倉庫のマスター/ディテール階層を示しています。マスター・パネルの「次の行」ボタンをクリックすると、(製品IDで識別された)次の製品がマスター・パネルに表示され、ディテール・パネルが更新されてこの製品を在庫として持つ倉庫と数量のリストが表示されます。

6.3.5.2 UIコントロール・ヒントのテスト

エンティティ・ベースのビュー・オブジェクトの属性は、基礎となるエンティティ・オブジェクト属性からコントロール・ヒントを継承します。データ・ビュー・ページに表示されるプロンプトにより、属性ごとにわかりやすいラベル・テキスト・コントロール・ヒントが正しく定義されているかどうかを確認できます。エンティティ・オブジェクトにヒントを設定する方法の詳細は、5.13項「ビュー・オブジェクトの属性のコントロール・ヒントの定義」を参照してください。

6.3.5.3 ビジネス・ドメイン・レイヤーの検証のテスト

定義した検証規則に応じて、無効な値を入力して検証例外のトリガーおよび検証を試行できます。たとえば、レンジ検証規則を定義した場合、レンジ外の値を入力し、次のようなエラーが表示されるのを確認します。

(oracle.jbo.AttrSetValException) Valid product codes are between 100 and 999

ツールバーで「ロールバック」ボタンをクリックし、データを以前の状態に戻してください。

6.3.5.4 代替言語のメッセージ・バンドルおよびコントロール・ヒントのテスト

アプリケーションにおいて、リソース・メッセージ・バンドル内に代替言語を定義する場合、これらの言語を認識するようにビジネス・コンポーネント・ブラウザを構成できます。設定したら、ビジネス・コンポーネント・ブラウザで「ロケール」メニューを表示し、利用可能な言語の中から選択できます。

ビジネス・コンポーネント・ブラウザのデフォルト言語を指定するには:

  1. JDeveloperの「ツール」から、「プリファレンス」を選択します。

  2. 選択パネルで「ビジネス・コンポーネント」を展開し、「テスター」を選択します。

  3. ビジネス・コンポーネント・ブラウザでエンティティ・ベースのビュー・オブジェクトを実行するには、データ・モデルのツリーを展開し、目的のビュー・オブジェクト・ノードをダブルクリックします。

  4. ビジネス・コンポーネント・ブラウザ・ページで、リソース・メッセージ・バンドルを作成したロケールを「選択されたもの」リストに追加します。

または、特定のアプリケーション・モジュール構成に対してADFビジネス・コンポーネントのランタイム構成プロパティを設定することによっても、デフォルト言語を構成できます。これらのランタイム・プロパティは、ビジネス・コンポーネント・ブラウザがデフォルトとして表示する言語も決定します。構成に対する「構成の編集」ダイアログで、「プロパティ」タブを選択し、国と言語に対して目的の国コードを入力します。たとえば、イタリア語を指定するには、次の2つのプロパティに対してITおよびitと入力します。

  • jbo.default.country = IT

  • jbo.default.language = it

ビジネス・コンポーネント・ブラウザで言語メッセージ・バンドルをテストすることで、コントロール・ヒントの翻訳が正しく配置されているかどうかを検証できます。または、メッセージ・バンドルが特定の属性の日付書式を定義している場合は、ツールによって日付書式の変更(たとえば、04/12/2013から12/04/2013へ)を検証できます。

6.3.5.5 エンティティ・オブジェクトの慣用名を参照するビュー・オブジェクトのテスト

データをスクロールするか、ビジネス・コンポーネント・ブラウザのツールバーにある「ビュー基準の指定」ボタンを使用して検索すると、外部結合を使用するようにエンティティ・ベースのビュー・オブジェクトの問合せのWHERE句を正しく変更したかどうかを検証できます。想定どおりに行が表示されるはずです。

マスター・ビュー・オブジェクトの主キー属性の変更も試行できます。これにより、対応する参照情報が新しい主キー値を反映するように自動的に更新されているかどうかを検証できます。

ビュー・オブジェクト・レベルで定義したコントロール・ヒントにより、基礎となるエンティティ・オブジェクトから一般的に継承されるコントロール・ヒントが上書きされたかどうかは、ビジネス・コンポーネント・ブラウザを使用して検証します。複数の属性が同じラベル・テキストを共有していることに気付いた場合は、ビュー・オブジェクト・レベルで目的の属性に対するコントロール・ヒントを編集できます。たとえば、「ラベル・テキスト」ヒントを、RegisteredDate 属性は「Member Since」ProvisionedFlag属性は「Provisioned?」に設定します。

6.3.5.6 行の作成およびデフォルト値の生成のテスト

エンティティ・ベースのビュー・オブジェクトを表示する際に、ビュー・オブジェクト・インスタンスに対してビジネス・コンポーネント・ブラウザのツールバーの「行の作成」ボタンをクリックし、新しい空白の行を作成します。宣言的なデフォルト値があるフィールドの場合、その値が空白行に表示されます。DBSequence値の属性を使用すると、新しい行に一時値が表示されます。すべての必須フィールドに入力した後、「コミット」ボタンをクリックしてトランザクションをコミットします。コミットが成功した後、トリガーによって割り当てられた実際の主キーがフィールドに表示されます。

6.3.5.7 新しいディテール行の外部キーが正しいかどうかのテスト

ビジネス・コンポーネント・ブラウザ・ツールバーの「行の作成」をクリックして既存のディテール・エンティティ・ベースのビュー・オブジェクト・インスタンスに新しい行を追加しようとすると、ビュー・リンクによって新しい行の外部キー属性値が現在のマスター・ビュー・インスタンス行に自動的に設定されることがわかります。

6.3.6ビジネス・コンポーネント・ブラウザでのマルチユーザー・シナリオのテスト方法

ビュー・オブジェクトとエンティティ・オブジェクトが実行時に連携する場合、マルチユーザー環境でアプリケーションを実行すると2つの例外が発生する可能性があります。これらの例外を予期するために、ビジネス・コンポーネント・ブラウザを使用して、テスト目的でマルチユーザー環境をシミュレートできます。たとえば、アプリケーションにビュー・オブジェクト問合せの編集フォームが表示される場合に、2人のユーザーがフォームで同じ属性を編集しようとすると、どのような動作が予想されるでしょうか。

予想される動作を理解するために、アプリケーション・モジュール上でビジネス・コンポーネント・ブラウザの2つのインスタンスを開き、同一のビュー・オブジェクト属性を編集する2人のユーザーをシミュレートします。2つのインスタンスを開いたまま、どのようにマルチユーザー例外が発生するかを表す次の2つのテストを実行します。

  • ビジネス・コンポーネント・ブラウザの1つのインスタンスで、既存のビュー・オブジェクトの属性を変更し、このフィールドから次に進みます。次に、もう1つのBrowserインスタンスで、同じビュー・オブジェクトの属性を同じように変更し、変更をコミットしてみます。2人目のユーザーには、oracle.jbo.AlreadyLockedExceptionが発生します。

    ここで、ビジネス・コンポーネント・ブラウザの「接続」ダイアログの「プロパティ」ページで、jbo.locking.modeの値をpessimisticに変更し、テストを繰り返して試行します(デフォルト・モードはoptimisticに設定されています)。エラーが発生するのは、2人目のユーザーが変更をコミットした後ではなく、値を変更した直後であることがわかります。

  • ビジネス・コンポーネント・ブラウザの1つのインスタンスで、既存のビュー・オブジェクトの属性を変更し、このフィールドから次に進みます。次に、もう1つのブラウザ・インスタンスで、同じビュー・オブジェクトの属性を変更せずに取得してみます。最初のウィンドウに戻り、変更をコミットします。2人目のユーザーが同じ属性を変更しようとすると、oracle.jbo.RowInconsistentExceptionが発生します。これは、2人目のユーザーが行をエンティティ・キャッシュに取得した後に、行が別のユーザーによって変更されてコミットされたためです。

6.3.7 ブラウザを実行する前の構成オプションのカスタマイズ方法

「ビジネス・コンポーネント構成の選択」ダイアログを使用して、事前定義済の構成を選択し、実行時構成プロパティの名前付きセットを使用してツールを実行できます。また、 「構成の選択」ダイアログの「プロパティ」タブでは、選択済の構成設定を参照したり、ブラウザの現在の実行に対する構成の設定をオーバーライドしたりできます。たとえば、「プロパティ」タブを開いて、目的の国コード(たとえば、イタリアを表すIT)を使用して次の2つのプロパティを設定することにより、ビジネス・コンポーネント・ブラウザの単一のインスタンスに対してUIコントロール・ヒントのデフォルト言語を変更できます。

  • jbo.default.country = IT

  • jbo.default.language = it


ヒント:

構成に対して永続的な変更を行う場合は、Configuration Managerを使用して、現在の構成をコピーし、目的のプロパティ・セットを設定した構成を新たに作成できます。たとえば、イタリア語のテストを行う場合はいつでも、デフォルトのUserServiceLocal構成ではなくUserServiceLocalItalian構成を使用するように選択するのみですみます。


6.3.8 ADFビジネス・コンポーネント・デバッグ診断を有効化する方法

ビジネス・コンポーネント・ブラウザを起動する際、データ・モデル・プロジェクトの現在の実行構成がJavaシステム・パラメータjbo.debugoutput=consoleを含むように設定されている場合、JDeveloperのログ・ウィンドウに移動するよう指示するメッセージとともに、ADFビジネス・コンポーネント・デバッグ診断を有効化できます。


注意:

名前は類似していますが、JDeveloperプロジェクトの実行構成は、ADFアプリケーション・モジュールの構成とは異なります。前者はプロジェクト・プロパティの一部ですが、後者はアプリケーション・モジュール・コンポーネントとともにbc4j.xcfgファイルに定義され、「ビジネス・コンポーネント構成の編集」ダイアログを使用して編集されます。


システムのデバッグ出力プロパティを設定するには、データ・モデル・プロジェクトの「プロジェクト・プロパティ」ダイアログの実行/デバッグ/プロファイル・ページを開きます。「編集」をクリックして、選択した実行構成を編集し、次の文字列をページ内の「Javaオプション」フィールドに追加します。

-Djbo.debugoutput=console

次回、ビジネス・コンポーネント・ブラウザを実行し、ビュー・オブジェクトをダブルクリックすると、例6-1に示すように、コンソールに詳細な診断結果が表示されます。診断を使用して、アプリケーションに対するフレームワーク・コンポーネントの処理をすべて視覚化できます。

例6-1 ビジネス・コンポーネント・ブラウザの診断結果

  :
[355] Oracle SQLBuilder: Registered driver: oracle.jdbc.OracleDriver
[356] Creating a new pool resource
[357] **** DBTransactionImpl establishNewConnection
[358] Successfully logged in
[359] JDBCDriverVersion: 11.1.0.7.0-Production
[360] DatabaseProductName: Oracle
[361] DBTransactionImpl initTransaction
[362] Replacing: null with: StoreServiceAM_AddressesPageDef
[363] Replacing: null with: StoreServiceAM_MostPopularProductsByCategoriesPageDef
...
[537] Orders ViewRowSetImpl.execute caused params to be "un"changed
[538] Column count: 41
[539] ViewObject: Orders Created new QUERY statement
[540] Orders>#q computed SQLStmtBufLen: 952, actual=865, storing=895
[541] SELECT OrderEO.ORDER_ID, OrderEO.ORDER_DATE, OrderEO.ORDER_SHIPPED_DATE,
       FROM ORDERS OrderEO ORDER BY OrderEO.ORDER_DATE desc
[542] Bind params for ViewObject: Orders

このプロパティの他の有効な値は、silent(指定されていない場合、デフォルト)およびfileです。fileオプションを選択すると、診断はsystem tempディレクトリに書き込まれます。


ヒント:

JDeveloper実行構成は個別に作成でき、1つはADFビジネス・コンポーネント・デバッグ診断を有効にして、もう1つはデバッグ診断なしにすることができます。適切なプロジェクト実行構成を選択することにより、JDeveloperの実行でデバッグ診断を使用するかどうかを簡単に変更できます。


6.3.9 ビュー・オブジェクトとエンティティ・オブジェクトが連携した場合の実行時の処理

ビュー・オブジェクトとエンティティ・オブジェクトにより、すべてのエンタープライズ・アプリケーション開発者が実行する必要のある次の2つの重要なジョブが単独で簡略化されます。

  • SQL問合せ結果の操作

  • データベース表内の行の変更および検証

エンティティ・ベースのビュー・オブジェクトは、エンド・ユーザーが表示または変更できるようにする必要のあるデータを任意に選択して問い合せることができます。エンド・ユーザーによる変更が可能なデータは、再使用可能なビジネス・ドメイン・レイヤーによって検証および保存されます。開発者が指定するのは、開発者のみが把握できる重要事項です。

  • ビジネス・ドメイン・レイヤーにどのビジネス・ロジックを適用するかの決定

  • 画面に表示する必要のあるデータを記述する問合せの決定

これらにより、開発者のアプリケーションが独自のものになります。実装の残りの詳細部分は、エンティティ・ベースのビュー・オブジェクトに組み込まれた機能によって処理されます。


注意:

行キーおよびエンティティ・キャッシュがトランザクションで果す役割について理解することは、エンティティ・ベースのビュー・オブジェクトの本質を明確にするために役立つ重要な概念です。これら2つの概念は、6.4.1項「ビュー・オブジェクトのデフォルト行セットを使用した操作のViewObjectインタフェース・メソッド」で説明します。


6.3.9.1 ビュー・オブジェクトによる問合せ実行時に発生する処理

エンティティ・ベースのビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加した後、問合せの実行時に行われる処理を確認できます。読取り専用ビュー・オブジェクトの場合と同様、エンティティ・ベースのビュー・オブジェクトが標準のJDBC (Java Database Connectivity) APIを使用してデータベースにSQL問合せを直接送信し、データベースが結果セットを生成します。ただし、読取り専用ビュー・オブジェクトの場合とは異なり、エンティティ・ベースのビュー・オブジェクトは、データベースの結果セットの各行を取得するときに、関連付けられているエンティティ・オブジェクトの慣用名に基づいて行属性を分割します。この分割の際、各ビュー・オブジェクトのエンティティ・オブジェクトの慣用名に適切なタイプのエンティティ・オブジェクト行が作成され、問合せによって取得された関連属性がこれらのエンティティ行に移入され、このようなエンティティ行がそれぞれ個別のエンティティ・キャッシュに格納されます。これにより、データの複製コピーを格納するかわりに、ビュー行は、これを構成するエンティティ行部分を指し示すだけでになります。

図6-12は、エンティティ・キャッシュにより、2つのエンティティ・ベース・ビュー・オブジェクトの結果セット属性がどのように分割されるかを示しています。この例では、データベース結果セットで強調表示された行は、主キー112Orderエンティティ行と、主キー301CustomerInfoエンティティ行に分割されています。

6.4.1.2項「エンティティ・キャッシュがトランザクションで果す役割」で説明するように、findByPrimaryKey()を使用してキャッシュに取り込んだエンティティ行には、エンティティ・オブジェクトのすべての属性が含まれています。一方、エンティティ・ベースのビュー・オブジェクトの問合せ結果の行を分割して作成されたエンティティ行には、問合せ結果に表れる属性の値のみが含まれます。これには完全な属性セットは含まれていません。このようにエンティティ行が部分的に移入されることにより、実行時のパフォーマンスが大幅に最適化されます。

一般的なエンタープライズ・アプリケーションで変更される行と比較して、取得される行の比率が非常に高くなるため、表示する必要がある属性のみをメモリーに読み込むことにより、常にすべての属性をメモリーに読み込む場合よりもメモリーを節約できます。

図6-12 エンティティ・キャッシュのエンティティ行に分割されるビュー行

エンティティ・キャッシュのエンティティ行に分割されるビュー行

このような方法で問合せ結果のデータを基礎となるエンティティ行の構成要素部分に分割すると、現在のトランザクションが変更された場合、問い合せた結果のデータを含むすべての行で整合している結果が表示されるという、重要な利点が得られます。つまり、あるビュー・オブジェクトで顧客301PaymentType属性を変更できる場合、顧客301PaymentType属性を表示する任意のエンティティ・ベースのビュー・オブジェクトのすべての行が即座に更新され、変更が反映されます。顧客301に関連付けられたデータがCustomerInfoエンティティ・キャッシュで主キー301を持つエンティティ行に格納されるのは1回のみであるため、オーダーのPaymentType属性を問い合せたビュー行はどれも、この単一のエンティティ行を指し示すことになります。

このような実装の詳細は、ビュー・オブジェクトの行セット内の行を操作するクライアントに対しては完全に非表示にされます。クライアントは、ビュー行を操作して属性を取得して設定する際、これらの属性がその背後でどのようにエンティティ行に関連付けられているかには気付きません。

6.3.9.2 ビュー行属性の変更時の処理

ユーザーがビュー行属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、エンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。

図6-13は、ユーザーがエンティティ・マップされた属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性Statusが、検証規則が定義されているエンティティ・オブジェクトの慣用名にマップされています。

  1. ユーザーがStatus属性の値をShipに設定しようとします。

  2. StatusOrderエンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Orderエンティティ・キャッシュ内で主キー112を持つ、基礎となるエンティティ行に設定されている属性を委譲します。

  3. Orderエンティティ・オブジェクトのStatus属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。

    Status属性の検証規則によってShipDate属性がプログラム的に参照されるとします(たとえば、Orderは発注日と同日に出荷済にはできないというビジネス・ルールを適用する必要がある場合など)。ShipDateは、問合せによって取得されたOrder属性ではないため、Orderエンティティ・キャッシュ内に部分的に移入されたエンティティ行にはありません。

  4. ビジネス・ルールでエンティティ・オブジェクトのすべての属性を常に参照可能にするため、エンティティ・オブジェクトはこの状況を検出し、主キーによって変更されるエンティティ行についてOrder エンティティ・オブジェクト属性のセット全体を失敗にします(主キーはビュー・オブジェクトに適用される各エンティティ・オブジェクトの慣用名に表示されます)。

  5. 属性レベルの検証がすべて成功した後、エンティティ・オブジェクトでは、最初の属性の変更を許可する前にORDERS表でこの行にロックをかけます。

  6. この行をロックできた場合、行内のStatus属性の設定が成功し、エンティティ行でこの値が変更されます。


注意:

jbo.locking.mode構成プロパティは、行のロック方法を制御します。デフォルト値はoptimisticです。通常、Fusion Webアプリケーションでは、このデフォルト設定のoptimisticを使用するため、トランザクションのコミット時まで行はロックされません。pessimisticロック・モードの場合、エンティティ・キャッシュで行に対する変更を許可する前に行のロックを可能にする必要があります。


図6-13 エンティティに委譲されるビュー行属性の更新

エンティティに委譲されるビュー行属性の更新

6.3.9.3 外部キー属性の変更時の処理

ユーザーが外部キーの属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、外部キーのエンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。また、変更された外部キー属性のビュー行に、すべての参照されたエンティティ・オブジェクトの正しい属性が反映されます。

図6-14は、ユーザーが外部キーのエンティティ・マップ属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性CustomerInfoIdは、エンティティ・オブジェクトの慣用名Orderにマップされており、ここでこの属性は別のエンティティ・オブジェクトであるCustomerInfoと関連付けられます。

  1. ユーザーがCustomerInfoId属性の値を300に設定しようとします。

  2. CustomerInfoIdOrderエンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Orderエンティティ・キャッシュ内で主キー112を持つ、基礎となるエンティティ行に設定されている属性を委譲します。

  3. Orderエンティティ・オブジェクトのCustomerInfoId属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。

  4. この行はすでにロックされているため、行内のCustomerInfoId属性の設定が成功し、エンティティ行でこの値が変更されます。

  5. Orderエンティティ・オブジェクトの慣用名のCustomerInfoId属性は、CustomerInfoエンティティ・オブジェクトに関連付けられているため、外部キー値をこのように変更すると、ビュー行で、顧客301の現在のエンティティ行部分が、新しいCustomerInfoId = 300に対応するエンティティ行に置き換えられます。これにより、オーダー112のビュー行が300のエンティティ行を指し示すよう効率的に変更できるため、ビュー行のPaymentTypeの値が更新され、この新しく割り当てられた顧客の参照情報が正しく反映されます。

図6-14 外部キーの更新後に新しいエンティティを指し示すビュー行

更新後に新しいエンティティを指し示す外部キー

6.3.9.4 トランザクションのコミット時の処理

変更に問題がなく、トランザクションをコミットするとします。図6-15に示すとおり、次の2つの基本手順があります。

  1. Transactionオブジェクトにより、保留中の変更リスト内の無効なエンティティ行が検証されます。

  2. 保留中の変更リスト内のエンティティ行がデータベースに保存されます。

この図は、1つの変更済エンティティ・オブジェクトの検証処理が他のエンティティ・オブジェクトに対する変更にプログラム的に影響する前に行う、手順1のループを示します。保留中の変更リスト上で無効なエンティティのリストが処理された後、リストにまだエンティティが残されている場合、トランザクションで別のパスが実行されます。リストのパススルーは最大10回行われます。この時点でまだ無効なエンティティ行がある場合は通常、ビジネス・ロジックにエラーがあり、このビジネス・ロジックを調査する必要があるため、例外がスローされます。

図6-15 トランザクションのコミット時に行われる無効なエンティティの検証とエンティティの保存

Transactionによる無効なエンティティの検証

6.3.9.5 ビュー・オブジェクトでのデータの再問合せ時の処理

ビュー・オブジェクトの問合せを再実行する場合、デフォルトでは、最新の結果セットを読み込むための準備中、現在の行セット内のビュー行は無視されます。ただし、このビュー・オブジェクト操作はエンティティ・キャッシュには直接影響しません。この場合、ビュー・オブジェクトがデータベースに対してSQLを送信することによってプロセスが再開され、データベースの結果セット行が取得され、エンティティ行部分に分割されます。


注意:

通常、ビュー・オブジェクトでデータの問合せを再実行する場合、この操作では最新のデータベース情報を取得します。かわりにビュー・オブジェクトの問合せ対象をキャッシュ内の既存のエンティティ行のみ、またはすでにビュー・オブジェクトの行セット内にある既存の行に制限して、データベースのラウンドトリップを回避する場合は、39.5項「行セットのメモリー内でのソート処理とフィルタ処理の実行」を参照してください。


6.3.9.5.1 問合せの再実行時の変更なしの属性の処理

問合せの再実行時におけるこのエンティティ行分割プロセスの一環として、エンティティ行の属性が変更されていない場合、エンティティ・キャッシュ内の値が更新され、新しい問合せ結果の値が反映されます。

6.3.9.5.2 問合せの再実行時の変更されたの属性の処理

一方、現在のトランザクションでエンティティ行属性の値が変更されている場合、問合せ再実行時のエンティティ行の分割プロセスでは、値はリフレッシュされません。現在のトランザクションでコミットされない変更はそのまま残されるため、エンド・ユーザーの論理作業ユニットは保持されます。任意のエンティティ属性値の場合と同様、これらの保留中の変更は、変更済エンティティ行を参照する任意のエンティティ・ベースのビュー・オブジェクト行に継続して表示されます。


注意:

エンド・ユーザーによる行の挿入および削除はエンティティ・キャッシュでも管理されるため、問合せの再実行時に、新規行を表示して削除済の行をスキップできます。新しい行の動作の詳細は、39.1.2項「同じエンティティに基づくビュー・オブジェクトでの新しい行の一貫性の保持」を参照してください。


たとえば、図6-16は、ユーザーがOrdersビュー・オブジェクト・インスタンスを使用する別のページにドリルダウンし、オーダー112に関する詳細を取得するシナリオを示しており、これは現在のトランザクションの保留中の変更のコンテキストで発生します。このビュー・オブジェクトには、プライマリOrdersの慣用名と、CustomerInfoの参照の慣用名の、2つのエンティティ・オブジェクトの慣用名があります。問合せ結果がエンティティ行に分割されると、前のOrderInfoビュー行で変更されたものと同じOrderエンティティ行を指し示すことになります。つまり、エンド・ユーザーには保留中の変更が正しく表示され、オーダーはこのトランザクションのsking に割り当てられています。

図6-16 エンティティ・キャッシュにマージされる、個別ビュー・オブジェクトのエンティティ属性セット

様々なビュー・オブジェクトをキャッシュでマージ
6.3.9.5.3 問合せの再実行時の属性のサブセットのオーバーラップの処理

2つの異なるビュー・オブジェクトが、参照情報の2つの異なるサブセットを取得でき、属性の一致するセットの有無にかかわらず、結果がマージされます。たとえば、図6-16もこの状況を示しており、Ordersビュー・オブジェクトはユーザーのEmailを問い合せていますが、OrderInfoビュー・オブジェクトはユーザーのPaymentOptionを問い合せています。この図は、実行時に行われる処理を示しており、取得した行を分割する際に、すでにキャッシュ内にある部分的に移入されたエンティティ行とは異なる属性セットがエンティティ行部分に含まれる場合、属性はマージされます。その結果、キャッシュ内の部分的に移入されたエンティティ行に、オーバーラップするユーザー属性のサブセットが統合されます。一方、キャッシュ内になかったjchen(ユーザー302)の場合、新しいエンティティ行にはEmail属性のみが含まれ、PaymentOptionは含まれません。

6.3.10 ビュー・オブジェクトの実行時パフォーマンスの最適化について

ビュー・オブジェクトには、SQLの実行方法とデータベースからデータをフェッチする方法を制御するチューニング・パラメータが用意されています。これらのチューニング・パラメータは、ビュー・オブジェクトの実行時パフォーマンスで重要な役割を果たします。アプリケーションでフェッチ・オプションが正常にチューニングされないと、ビュー・オブジェクトが必要以上の量のデータをフェッチし、データベースへのラウンドトリップの回数が非常に増える場合があります。

表6-2に示すように、概要エディタの「一般」ページの「チューニング」セクションでは、フェッチ・オプションを設定できます。

表6-2 ビュー・オブジェクトのパフォーマンスをチューニングするためのパラメータ

フェッチをチューニングするパラメータ 使用方法

フェッチ・モード

デフォルトのフェッチ・オプションは「すべての行」オプションで、「必要に応じて」(FetchMode="FETCH_AS_NEEDED")、または「一度にすべて」(FetchMode="FETCH_ALL")のどちらのオプションが適切かに応じて取得されます。「必要に応じて」オプションでは、ビュー・オブジェクトでのexecuteQuery()操作において、まず表示の最初のページを埋めるために必要な数の行のみが取得されます(この行数は、ビュー・オブジェクトの範囲サイズに基づいて設定されます)。

フェッチ・サイズ

「次の単位で」フィールドでは、「フェッチ・モード」オプションと連携して、データベースから一度にフェッチされるレコード数(ビュー・オブジェクトXMLのFetchSize)を制御します。デフォルト値は1です(1行のみがフェッチされる場合を除き、パフォーマンスが低下します)。推奨構成として、この値をn+1に設定することをお薦めします。nはユーザー・インタフェースに表示される行数です。

最大フェッチ・サイズ

ビュー・オブジェクトのデフォルトの最大フェッチ・サイズは-1で、ビュー・オブジェクトでフェッチできる行数に制限がないことを示します。結果セットにn行のデータしか含まれない場合は、「行番号までのみ」のオプションを選択して、nに設定してください。開発者は、setMaxFetchSize(n)をコールしてプログラム的に設定することも、ビュー・オブジェクトXMLにパラメータMaxFetchSizeを手動で追加することもできます。

WHERE句が単一の行を取得すると予想されるビュー・オブジェクトの場合は、オプションを「最大で1行」に設定します。このオプションを指定すると、ビュー・オブジェクトはユーザーがそれ以上の行を期待していないことを認識し、さらに行がある場合に通常行うテストをスキップします。

前述のように、最大フェッチ・サイズを0に設定すると、ビュー・オブジェクトは挿入専用になります。この場合は、選択問合せは発行されないため、行はフェッチされません。

アプリケーションのすべてのビュー・オブジェクト問合せに対してグローバルなしきい値を指定する必要がある場合は、adf-config.xmlファイルで「行フェッチ制限」プロパティを設定できます。このプロパティを設定することで、個別の問合せ操作に対して「最大フェッチ・サイズ」の変更を行う必要がなくなります。個別のビュー・オブジェクトにフェッチ制限を設定する場合、これらのケースでは「行フェッチ制限」設定は無視されます。「行フェッチ制限」の詳細は、39.1.1項「最初のn行をフェッチするためのビュー・オブジェクト最大フェッチ・サイズの制限」を参照してください。

転送専用モード

データセットのトラバースで転送しか実行されない場合は、転送専用モードを使用すると、データセットを反復する場合のパフォーマンスが向上します。転送専用モードは、ビュー・オブジェクトでsetForwardOnly(true)をコールしてプログラム的に設定できます。転送専用モードを設定すると、データセットがトラバースされるときに、前の行セットがキャッシュされるのを防ぐこともできます。


ビュー・オブジェクトをチューニングする場合は、次の点も考慮する必要があります。

  • 大規模なデータ・セット: ビュー・オブジェクトは、ユーザーが結果の特定のページにジャンプできるように、大規模なデータ・セット内でページ移動するメカニズムを備えています。この機能は、ビュー・オブジェクトでsetRangeSize(n)setAccessMode(RowSet.RANGE_PAGING)の順にコールすることによって設定します(nは、1ページに含める行数)。ユーザーがデータ・セット内の特定のページに移動する場合、アプリケーションはビュー・オブジェクトでscrollToRangePage(P)をコールするとページPに移動できます。範囲ページングでは、現在のページの行のみがフェッチされて、ビュー・オブジェクトの行キャッシュに入れられるため、1ページのデータを取得するたびに問合せ実行のコストがかかります。範囲ページングは、すべての行をフェッチしてビュー・オブジェクトの行キャッシュに入れるほうが有利な場合には適していません(たとえば、データ・セットのすべての行を読み取ってLOVを生成したり、小さいデータ・セットのレコードを前後にページ移動したりする必要がある場合です)。

  • スピルオーバー: JVMコンテナでメモリーが不足した場合に、データ・ソースを仮想メモリーとして使用する機能が用意されています。デフォルトでは、この機能は無効になっていますが、メモリーが不足した場合の最後の手段として、jbo.use.pers.coll=trueに設定することにより有効にできます。スピルオーバーを有効にすると、パフォーマンスが大きく影響を受ける場合があります。

  • SQLスタイル: SQL92準拠の汎用データベースへの接続に汎用SQL92 SQLスタイルを使用すると、ビュー・オブジェクトの一部のチューニング・オプションが正常に機能しなくなります。汎用SQL92 SQLスタイルを選択することにより最も影響を受けるパラメータは、フェッチ・サイズです。SQL92 SQLスタイルを使用すると、ビュー・オブジェクトの構成に関係なく、フェッチ・サイズがデフォルトで10行に設定されます。SQLスタイルは、データベース接続の定義時に設定できます。デフォルトでは、SQLスタイルはOracleです。SQLスタイルを手動で上書きする場合は、起動時にパラメータ-Djbo.SQLBuilder="SQL92"をJVMに渡すこともできます。

また、データベースのパフォーマンスを向上するために、ビュー・オブジェクトの関連するSQLをチューニングするための次のオプションも用意されています。

  • バインド変数: ビュー・オブジェクトに関連付けられた問合せに、実行ごとに変更される可能性がある値が含まれる場合は、バインド変数を使用します。問合せでバインド変数を使用すると、データベースで問合せを再解析する必要なく、問合せを再実行できます。バインド変数は、ビュー・オブジェクトの概要エディタの「問合せ」ページでビュー・オブジェクトに追加できます。詳細は、5.10項「バインド変数の使用」を参照してください。

  • 問合せオプティマイザ・ヒント: ビュー・オブジェクトでは、ヒントをデータベースに渡して、関連する問合せに使用される実行計画に影響を与えることができます。オプティマイザ・ヒントは、ビュー・オブジェクトの概要エディタの「チューニング」セクションの「データベースから取得」グループ・ボックスで指定できます。オプティマイザ・ヒントの詳細は、39.2.4.3項「必要に応じた問合せオプティマイザ・ヒントの指定」を参照してください。

6.4 ビュー・オブジェクト・インスタンスのプログラムによるテスト

少なくとも1つのビュー・オブジェクト・インスタンスを含む、操作中のアプリケーション・モジュールをテストする準備ができたら、単純なテスト・クライアント・プログラムを構築して、含まれるビュー・オブジェクト・インスタンスにあるデータを使用したプログラムによる操作の基礎を示すことができます。

アプリケーション・モジュールのデータ・モデルにアクセスするクライアントの視点からは、読取り専用ビュー・オブジェクトを操作するAPIと、エンティティ・ベースのビュー・オブジェクトを操作するAPIは同一のものです。機能的な主な相違点は、エンティティ・ベースのビュー・オブジェクトでは、ビュー・オブジェクトのデータを完全に更新できる点です。エンティティ・ベースのビュー・オブジェクトを含むアプリケーション・モジュールは、作業ユニットを定義し、トランザクションを管理します。この項では、Fusion Order DemoのStoreFrontAMアプリケーション・モジュールを操作する簡単な4つのテスト・クライアント・プログラムを使用して、次について説明します。

6.4.1 ビュー・オブジェクトのデフォルト行セットを使用した操作のViewObjectインタフェース・メソッド

oracle.jboパッケージのViewObjectインタフェースには、データ取得タスクを簡単に実行するメソッドが用意されています。例に使用されるこれらのメソッドの一部には、次のものが含まれます。

  • executeQuery(): ビュー・オブジェクトの問合せを実行し、その結果の行セットを移入します。

  • setWhereClause(): 実行時に動的条件を追加して検索を絞り込みます。

  • setNamedWhereClauseParam(): 名前付きバインド変数の値を設定します。

  • hasNext(): 行セット・イテレータが結果の最終行に到達したかどうかをテストします。

  • next(): 行セット・イテレータを行セット内の次の行へ進めます。

  • getEstimatedRowCount(): ビュー・オブジェクトの問合せが戻す行の数をカウントします。

ビュー・オブジェクトを操作する場合は、通常、単一の結果行セットのみを1回で操作します。このきわめて一般的なユースケースを単純化するために、図6-17に示すように、ビュー・オブジェクトにはデフォルトのRowSetが含まれ、ここにデフォルトのRowSetIteratorが含まれています。デフォルトのRowSetIteratorにより、デフォルト行セットに自動的に適用されることを認識しながら、ViewObjectコンポーネント自体でデータ取得メソッドのすべてを直接コールできるようになります。

図6-17 デフォルトのRowSetおよびRowSetIteratorが含まれているビュー・オブジェクト

行セットとイテレータが含まれる行オブジェクト

注意:

第39章「ビュー・オブジェクトの高度な手法」では、単一のビュー・オブジェクトを使用して複数の異なる結果行セットを生成する状況が示されています。また、1つの行セットに対して複数の異なる行セット・イテレータを作成するシナリオも説明されています。ただし、多くの場合は単一のイテレータのみ必要です。


このガイドで「ビュー・オブジェクトの行を使用して操作中」という表現を使用した場合は、正確にはビュー・オブジェクトのデフォルト行セットの行を使用して操作するということを意味しています。同様に、「ビュー・オブジェクトの行全体で反復処理する」という表現は、正確にはビュー・オブジェクトのデフォルト行セットのデフォルト行セット・イテレータを使用して、その行をループするという意味です。

6.4.1.1 ビュー行またはエンティティ行におけるキー・オブジェクトの役割

ビュー行を操作するときは、oracle.jboパッケージの中のRowインタフェースを使用します。図6-18に示すように、このインタフェースには、任意の行を識別するKeyオブジェクトへのアクセスに使用できる、getKey()と呼ばれるメソッドが含まれています。Rowインタフェースは、oracle.jbo.serverパッケージ内の Entityインタフェースによって拡張されます。この関係は、エンティティ行という用語が適切であることの具体的な理由になります。エンティティ行がビジネス・ロジックのカプセル化やデータベース・アクセスの処理のための追加機能をサポートしている場合でも、エンティティ行はRowとしてそのまま扱うことができます。

エンティティ・ベースのビュー・オブジェクトは、キーによる行の検索タスクを、基礎となるエンティティ行部分に委譲します。

前述のとおり、ビュー行とエンティティ行はどちらも単一属性または複数属性のキーをサポートしているため、特定のRowに関連付けられたKeyオブジェクトにより、キーを構成するすべての属性がカプセル化されます。Keyオブジェクトがある場合は、任意の行セットに対してfindByKey()メソッドを使用して、Keyオブジェクトに基づいて行を検索できます。findByKey()メソッドを使用してキーによってビュー行を検索すると、ビュー行ではエンティティ定義のfindByPrimaryKey()メソッドを使用して、ビュー行キーに属性を提供する各エンティティ行が検索されます。

読取り専用ビュー・オブジェクトの場合、このタスクを委譲する基礎となるエンティティ行がないため、主キー属性が1つでも検出されると、ビュー・オブジェクトの実装により、manageRowsByKeyフラグが自動的に有効になります。このため、読取り専用ビュー・オブジェクトの場合は、findByKey()メソッドが成功します。manageRowsByKeyフラグが有効でない場合、キーを使用して現在の行を設定するなどのUI操作は、findByKey()メソッドに依存するため機能しません。

図6-18 識別キーの取得をサポートしているビュー行またはエンティティ行

識別キーの取得をサポートしているエンティティ行

注意:

エンティティ・ベースのビュー・オブジェクトを定義する場合、デフォルトでは、すべてのエンティティ・オブジェクトの慣用名の主キー属性は、「キー属性」プロパティの設定がtrueとしてマークされます。更新不可能な参照エンティティ・オブジェクトの慣用名では、キー属性の「キー属性」プロパティを無効にしてください。更新可能なエンティティ・オブジェクトの慣用名の主キーに関連するビュー・オブジェクト属性は、複合ビュー行キーの一部である必要があるため、「キー属性」プロパティを無効にできません。


6.4.1.2 エンティティ・キャッシュがトランザクションで果す役割

アプリケーション・モジュールは、論理的な作業ユニットのトランザクション・コンテナです。実行時には、指定された名前の構成情報を使用してデータベース接続を確立し、トランザクション管理を付属のTransactionオブジェクトに委譲します。論理作業ユニットには、様々なタイプの複数のエンティティ行の検索や変更が含まれる場合があるため、Transactionオブジェクトには、現在のユーザーのトランザクションに関連するエンティティ行を保持するための作業領域として、エンティティ・キャッシュが用意されています。各エンティティ・キャッシュには単一のエンティティ・タイプの行が含まれるため、2つ以上のエンティティ・オブジェクトが関連するトランザクションでは、これらのエンティティ行の作業用コピーが個別キャッシュに保持されます。

エンティティ・オブジェクトの関連エンティティ定義を使用して、アプリケーション・モジュールで既存のエンティティ行を検索し、変更するためのコードを記述できます。図6-19に示すとおり、Orderエンティティ・オブジェクトのエンティティ定義に対してfindByPrimaryKey()をコールすると、そのキーを持つ行を取得できます。この行がまだエンティティ・キャッシュ内にない場合、エンティティ・オブジェクトによってこの行をデータベースから取得するための問合せが実行されます。この問合せにより、基礎となる表からエンティティ・オブジェクトのすべての持続属性が選択され、エンティティ・オブジェクトの主キー属性に対応する列に適したWHERE句を使用して行が検索されます。同一トランザクション中に同じエンティティ行をキーによって引き続き検索する場合、この行をキャッシュ内で検索することにより、データベースへのトリップを回避します。特定のエンティティ・キャッシュでは、主キーによってエンティティ行が索引付けされます。これにより、キャッシュ内でのエンティティ行の検索処理が速くなります。

アソシエーション・アクセッサ・メソッドを使用して関連エンティティ行にアクセスする場合、これらの行はエンティティ・キャッシュからも取得されます。関連エンティティ行がキャッシュ内にない場合は、データベースから取得されます。最後に、エンティティ・キャッシュは、新しいエンティティ行が保存されるまで保持される場所でもあります。つまり、createInstance2()メソッドを使用してエンティティ定義に対して新しいエンティティ行を作成する場合、このエンティティ行はエンティティ・キャッシュに追加されます。

図6-19 トランザクション中にエンティティ・キャッシュに格納されるエンティティ行

エンティティ・キャッシュに格納される行

エンティティ行を作成、変更または削除すると、このエンティティ行はトランザクションの保留中の変更リストに自動的に登録されます。Transactionオブジェクトに対してcommit()をコールすると、保留中の変更リストが処理され、まだ無効の新規または変更済エンティティ行があるかどうかが検証されます。保留リスト内のエンティティ行がすべて有効である場合、Transactionにより、データベースのSAVEPOINTが発行され、データベースへのエンティティ行の保存が調整されます。すべて正常に完了すると、最終的にデータベースのCOMMIT文が発行されます。問題が発生した場合、TransactionによってROLLBACK TO SAVEPOINTが実行され、ユーザーはエラーを修正するか、または再試行できるようになります。

アプリケーション・モジュールで使用されるTransactionオブジェクトは、単一のエンド・ユーザー・トランザクション用のエンティティ行の作業セットです。設計上、これは共有のグローバル・キャッシュではありません。データベース・エンジン自体は、複数の同時ユーザーを対象とした非常に効率的な共有グローバル・キャッシュです。ADFビジネス・コンポーネントでは、すべての作業で行われてきたデータベースの共有グローバル・キャッシュ機能の微調整を繰り返すのではなく、その結果が意識的に採用されています。refresh()メソッドをコールすると、データベースから単一のエンティティ・オブジェクトのデータをいつでもリフレッシュできます。Transactionオブジェクトに対してsetClearCacheOnCommit()またはsetClearCacheOnRollback()を使用すると、コミットまたはロールバック時にエンティティ・キャッシュを消去するかどうかを制御できます。デフォルトはそれぞれfalsetrueです。また、TransactionオブジェクトにはclearEntityCache()メソッドも用意されており、このメソッドを使用して、特定のエンティティ・タイプ(またはすべてのタイプ)のエンティティ行をプログラムで消去できます。エンティティ・キャッシュを消去すると、そのタイプのエンティティ行は、主キーによって次に検出されるか、エンティティ・ベースのビュー・オブジェクトによって取得されるときに、データベースから取得できます。

6.4.2 コマンドラインJavaテスト・クライアントの作成方法

テスト・クライアント・プログラムを作成するには、「新規ギャラリ」からアクセス可能なJavaクラスの作成ウィザードを使用します。

6.4.2.1 スケルトン・コードを使用したテスト・クライアントの作成

テスト・クライアント・プログラムを作成するときに「Javaクラスの作成」ウィザードを使用すると、プログラム・ファイルがソース・エディタで開き、事前定義済のコード・テンプレートからコードを追加してテスト・クライアントを作成することができます。

スケルトンJavaテスト・クライアントを作成するには:

  1. アプリケーション・ナビゲータで、テスト・クライアントを作成するプロジェクトを右クリックし、「新規」を選択します。

  2. 「新規ギャラリ」で、「一般」を展開し、「Java」「Javaクラス」の順に選択して、「OK」をクリックします。

  3. 「Javaクラスの作成」ダイアログで、TestClientなどのクラス名、oracle.fodemo.storefront.clientなどのパッケージ名を入力し、「拡張」フィールドがjava.lang.Objectとなっていることを確認します。

  4. 「オプション属性」で、「スーパークラスからのコンストラクタ」の選択を解除し、「mainメソッド」を選択します。

  5. 「OK」をクリックします。

    .javaはソース・エディタで開き、例6-2で示すように、スケルトン・コードが示されます。

例6-2 TestClient.javaのスケルトン・コード

package oracle.fodemo.storefront.client;
public class TestClient {
  public static void main(String[] args) {
       
  }
}

6.4.2.2 スケルトン・コードの変更によるテスト・クライアントの作成

テスト・クライアントのスケルトン・コードを作成したら、JDeveloperで利用可能な事前定義済のbc4jclientコードを使用してファイルの編集を開始できます。

bc4jclientコード・テンプレートを挿入するには:

  1. main()メソッドの本体にある空白行にカーソルを置き、bc4jclientコード・テンプレートを使用して必要なコードを数行作成します。

  2. bc4jclientという文字を入力し、[Ctrl]キーを押しながら[Enter]キーを押します。

    JDeveloperによって、例6-3に示すように、テンプレートを使用してクラス・ファイルが展開されます。

  3. amDefおよびconfig変数の値を調整して、アプリケーション・モジュール定義の名前と使用する構成の名前をそれぞれ反映します。

    例6-3では、変更した行は次のようになります。

    String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM";
    String config = "StoreServiceAMLocal";
    
  4. 最後に、コール内のビュー・オブジェクト・インスタンス名を、作業するfindViewObject()に変更します。アプリケーション・モジュールの概要エディタの「データ・モデル」ページで「データ・モデル」ツリーに表示される名前を正確に指定します。

    例6-3では、変更した行は次のようになります。

    ViewObject vo = am.findViewObject("Persons");
    

例6-3 TestClient.javaの拡張されたスケルトン・コード

package oracle.fodemo.storefront.client;
import oracle.jbo.client.Configuration;
import oracle.jbo.*;
import oracle.jbo.domain.Number;
import oracle.jbo.domain.*;
public class TestClient {
  public static void main(String[] args) {
    String        amDef = "test.TestModule";
    String        config = "TestModuleLocal";
    ApplicationModule am =
      Configuration.createRootApplicationModule(amDef,config);
    ViewObject vo = am.findViewObject("TestView");
    // Work with your appmodule and view object here
    Configuration.releaseRootApplicationModule(am,true);
  }
}

アプリケーション・モジュールに対するスケルトン・テスト・クライアントには、例6-4に示すようなソース・コードが含まれている必要があります。


注意:

9.10項「アプリケーション・モジュールのクライアント・インタフェースのプログラム的操作」における例では、このテスト・クライアント・サンプル・コードが拡張され、カスタム・アプリケーション・モジュール・サービス・メソッドのコールも説明されます。


例6-4 アプリケーション・モジュール・テスト・クライアント・プログラムの作業中スケルトン・コード

package oracle.fodemo.storefront.client;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

public class TestClient {

  public static void main(String[] args) {
    String  amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM";
    String  config = "StoreServiceAMLocal";
    ApplicationModule am =
                        Configuration.createRootApplicationModule(amDef,config);
    // 1. Find the Persons view object instance.
    ViewObject personList = am.findViewObject("Persons");
    // Work with your appmodule and view object here
    Configuration.releaseRootApplicationModule(am,true);
  }
}

// Work with your appmodule and view object hereを、テスト対象のビュー・オブジェクトを実行するコードに置き換えます。たとえば、ビュー・オブジェクトの問合せを実行し、戻される行の数を表示し、結果をループしてデータをフェッチしコンソールに出力するために、例6-5に示したコードをモデル・プロジェクトのコンポーネントに適合できます。

例6-5 マスター/ディテール・ビュー・オブジェクトのループおよびコンソールへの結果の出力

    // 2. Execute the query
    personList.executeQuery();
    // 3. Iterate over the resulting rows
    while (personList.hasNext()) {
        Row person = personList.next();
        // 4. Print the person's email
        System.out.println("Person: " + person.getAttribute("Email"));
        // 5. Get related rowset of Orders using view link accessor attribute
        RowSet orders = (RowSet)person.getAttribute("Orders");
        // 6. Iterate over the Orders rows
        while (orders.hasNext()) {
            Row order = orders.next();
            // 7. Print out some order attribute values
              System.out.println(" ["+order.getAttribute("OrderStatusCode")+"] "+
                                    order.getAttribute("OrderId")+": "+
                                    order.getAttribute("OrderTotal"));
              if(!order.getAttribute("OrderStatusCode").equals("COMPLETE")) {
                  // 8. Get related rowset of OrderItems
                  RowSet items = (RowSet)order.getAttribute("OrderItems");
                  // 9. Iterate over the OrderItems rows
                  while (items.hasNext()) {
                     Row item = items.next();
                     // 10. Print out some order items attributes
                     System.out.println("  "+item.getAttribute("LineItemId")+": "+
                                          item.getAttribute("LineItemTotal"));
                }
            }
        }
    }

最初の行では、executeQuery()メソッドをコールして、ビュー・オブジェクト問合せを実行します。これにより、ビュー・オブジェクトのhasNext()メソッドがfalseを戻すまで反復処理を行うwhile文を使用してループできる、ゼロまたは1行以上の行セットを生成します。ループ内では、コードで現行のRowpersonという名前の変数に入れてから、この現行のRowオブジェクト上でgetAttribute()メソッドを2回呼び出し、Email属性とOrders属性の値を取得して、オーダー情報をコンソールに出力します。2番目のwhile文では、オーダーの明細項目に対して同じタスクを実行します。

6.4.3 テスト・クライアント・プログラム実行時の処理

ConfigurationオブジェクトでのcreateRootApplicationModule()へのコールによって、使用するアプリケーション・モジュールのインスタンスが戻されます。デバッグ診断出力で示されるとおり、ADFビジネス・コンポーネント実行時クラスによって、必要に応じてXMLコンポーネント定義をロードして、設計時にデータ・モデルで定義されたアプリケーション・モジュールとビュー・オブジェクト・コンポーネントのインスタンスをインスタンス化します。アプリケーション・モジュール上のfindViewObject()メソッドによって、アプリケーション・モジュールのデータ・モデルからビュー・オブジェクト・インスタンスを名前で検索します。例6-5で示されているループの後、テスト・クライアントはConfigurationオブジェクトでreleaseRootApplicationModule()を実行します。これにより、アプリケーション・モジュールを使用して処理したことが通知され、アプリケーション・モジュールに使用されたデータベース接続のように、フレームワークでリソースをクリーン・アップできるようになります。

6.4.4 テスト・クライアントの実行について

createRootApplicationModule()およびreleaseRootApplicationModule()メソッドは、アプリケーション・モジュール・コンポーネントへのコマンドライン・アクセスの場合に非常に便利です。ただし、通常、ADFベースのWebまたはSwingアプリケーションのコンテキストでは、これら2行のコードを記述する必要はありません。レイヤーをバインドするADFモデルのデータとADFビジネス・コンポーネント・レイヤーを自動的に連携させることによって、これらのシナリオでユーザーのアプリケーション・モジュール・コンポーネントを取得およびリリースします。

6.4.5 行セットにおける行数計算の方法

getEstimatedRowCount()メソッドは、含まれている行数を判断するために、RowSetで使用されます。

long numReqs = reqs.getEstimatedRowCount();

getEstimatedRowCount()の実装によって最初にSELECT COUNT(*)の問合せが発行され、問合せから戻される行の数を計算します。問合せは、次のような文のビュー・オブジェクトの問合せ全体をラップすることにより、計算式で表されます。

SELECT COUNT(*) FROM ( ... your view object's SQL query here ... )

SELECT COUNT(*)問合せを使用すると、必ずしもすべての行自体を取得しなくても、ビュー・オブジェクトの行数にアクセスできるようになります。このアプローチにより、大量の行数を戻す問合せを操作する場合や、問合せの結果を操作する前に問合せから戻さうる行数をテストする場合に、重要な最適化を図ることができます。

推定行数が計算されると、後続のメソッドへのコールではCOUNT(*)問合せは再実行されません。この値は、次にこのビュー・オブジェクトの問合せが実行されるまでキャッシュされます(データベースから戻される新しい問合せ結果セットに、前回の問合せ実行時より多い、少ない、または異なる行が含まれる可能性があるためです)。推定行数は、現行トランザクションで保留中の変更、関連する新規行の数の追加、および戻された数から削除された行数の差引を考慮して自動的に調整されます。

getEstimatedRowCount()をオーバーライドして、アプリケーションの必要性に合せて、カスタムのカウント問合せを実行することもできます。

6.4.6 ビュー・リンク・アクセッサを使用したディテール・コレクションのアクセス方法

5.6.6.2項「ビュー・リンク・アクセッサを使用したディテール・コレクションへのプログラムによるアクセス」で説明しているように、ビュー・リンク・アクセッサを使用してディテール行のRowSetを取得すると、ビュー・オブジェクトの結果行セットで使用されるパターンと同じパターンを使用して、その行セットに含まれる行全体をループできます(例6-6を参照)。

例6-6 ディテール・コレクションへのアクセスに使用されるパターン

while (reqs.hasNext()) {
  Row curReq = reqs.next();
  System.out.println("--> (" + curReq.getAttribute("OrderId") + ") " + 
                     curReq.getAttribute("OrderTotal"));
}

例6-7は、PersonListビュー・オブジェクト・インスタンスを制限してperson_type_codeの値がCUSTであるユーザーのみを表示するために、動的なWHERE句を設定するmain()メソッドを示しています。さらに、executeAndShowResults()メソッドは、ビュー・リンク・アクセッサ属性にアクセスし、それぞれに対してリクエスト番号(PersonId)およびEmail属性を出力します。

ビュー・リンク・アクセッサを使用してディテール・コレクションにアクセスするには、次の基本的な手順に従います(例6-7を参照)。

  1. マスター・ビュー・オブジェクト・インスタンスを検索します。

  2. 問合せを実行します。

  3. マスター・ビュー・オブジェクトの行を反復処理します。

  4. ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。

  5. ディテール・ビュー・オブジェクトの行を反復処理します。

  6. 必要に応じて、ディテール行セット属性を操作します。


パフォーマンスに関するヒント:

行をループするために記述するコードで行を表示する必要がない場合は、終了した行セットでcloseRowSet()メソッドをコールできます。この方法では、メモリー使用を効率化できます。行セットの問合せは、その行セットに次にアクセスしたときに再実行されます。


例6-7 ビュー・リンク・アクセッサを使用したディテール行へのプログラムによるアクセス

package devguide.examples.readonlyvo.client;

import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

public class TestClient2 {
  public static void main(String[] args) {
    String amDef = "devguide.examples.readonlyvo.PersonService";
    String config = "PersonServiceLocal";
    ApplicationModule am = 
                        Configuration.createRootApplicationModule(amDef, config);
    // 1. Find the Persons view object instance.
    ViewObject vo = am.findViewObject("PersonList");
    // Add an extra where clause with a new named bind variable
    vo.setWhereClause("person_type_code = :ThePersonType");
    vo.defineNamedWhereClauseParam("ThePersonType", null, null);
    vo.setNamedWhereClauseParam("ThePersonType", "CUST");
    // Show results when :ThePersonType = 'CUST'
    executeAndShowResults(vo);
    Configuration.releaseRootApplicationModule(am, true);
  }
  private static void executeAndShowResults(ViewObject vo) {
    System.out.println("---");
    // 2. Execute the query
    vo.executeQuery();
    // 3. Iterate over the resulting rows of the Persons view object    while (vo.hasNext()) {
        Row curPerson = vo.next();
        // 4. Access the row set of Orders using the view link accessor attribute
        RowSet orders =(RowSet)curPerson.getAttribute("OrdersShippedToPurchaser");
        long numOrders = orders.getEstimatedRowCount();
        System.out.println(curPerson.getAttribute("PersonId") + " " + 
                           curPerson.getAttribute("Email")+" ["+
                           numOrders+" orders]");
        // 5. Iterate over the resulting detail rows
        while (orders.hasNext()) {
            Row curOrder = orders.next();
        // 6. Print out some Order attribute values
            System.out.println("--> (" + curOrder.getAttribute("OrderId") + ") " + 
                        curOrder.getAttribute("OrderTotal"));        }
    }
  }
}

TestClient2.javaを実行すると、例6-8に示すような出力が「ログ」ウィンドウに出力されます。各顧客がリストされ、オーダーした顧客ごとに、オーダーの合計が顧客の名前の下に表示されます。

例6-8 TestClient.javaの実行結果

---
121 AFRIPP [0 orders]
115 AKHOO [0 orders]
109 DFAVIET [0 orders]
114 DRAPHEAL [0 orders]
118 GHIMURO [0 orders]
126 IMIKKILI [0 orders]
111 ISCIARRA [0 orders]
110 JCHEN [0 orders]
127 JLANDRY [0 orders]
112 JMURMAN [0 orders]
125 JNAYER [0 orders]
119 KCOLMENA [0 orders]
124 KMOURGOS [0 orders]
129 LBISSOT [0 orders]
113 LPOPP [1 orders]
--> (1013) 89.99
120 MWEISS [1 orders]
--> (1003) 5000
108 NGREENBE [1 orders]
--> (1002) 1249.91
122 PKAUFLIN [0 orders]
116 SBAIDA [0 orders]
128 SMARKLE [0 orders]
117 STOBIAS [0 orders]
123 SVOLLMAN [0 orders]

デバッグ診断を有効にしてTestClient2.javaを実行すると、ビュー・オブジェクトによって実行されたSQL問合せが表示されます。ビュー・リンクのWHERE句条件は、PersonListビュー・オブジェクトで現在行のディテール・サービス・リクエストのフィルタリングを自動実行するために使用されます。

6.4.7 マスター/ディテール/ディテール階層の反復方法

別のネスト・レベルが含まれるマスター/ディテールの反復処理を行うには、次の基本的な手順に従います(例6-9を参照)。

  1. マスター・ビュー・オブジェクト・インスタンスを検索します。

  2. 問合せを実行します。

  3. 結果の行を反復処理します。

  4. 必要に応じて、マスター行セット属性を操作します。

  5. ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。

  6. ディテール行セットの行を反復処理します。

  7. 必要に応じて、ディテール行セット属性を操作します。

  8. ビュー・リンク・アクセッサ属性を使用して、関連する2番目のディテール・ビュー・オブジェクトの行セットを取得します。

  9. 2番目のディテール・行セットの行を反復処理します。

  10. 必要に応じて、2番目のディテール行セット属性を操作します。

例6-9では、もう1つ別のネスト・レベルを使用せずに、6.4.6項「ビュー・リンク・アクセッサを使用したディテール・コレクションのアクセス方法」で説明した、マスター/ディテール読取り専用ビュー・オブジェクトを反復するTestClientプログラムと同じAPIを使用しています。

既存のTestClient.javaクラスでJDeveloperの「リファクタ」→「複製」機能を使用する場合、それを簡単にクローニングしてTestClient2.javaクラスを作成できます。たとえば、例6-8TestClient.javaクラスは、この手法に適しています。

例6-9 マスター/ディテール/ディテール階層の反復

package oracle.fodemo.storefront.client;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

public class TestClient2 {
  
  public static void main(String[] args) {
    String    amDef =
                "oracle.fodemo.storefront.store.service.StoreServiceAM";
    String    config = "StoreServiceAMLocal";
    ApplicationModule am =
                Configuration.createRootApplicationModule(amDef,config);
    // 1. Find the Persons view object instance.
    ViewObject personList = am.findViewObject("Persons");
    // 2. Execute the query
    personList.executeQuery();
    // 3. Iterate over the resulting rows
    while (personList.hasNext()) {
    Row person = personList.next();
    // 4. Print the person's email
    System.out.println("Person: " + person.getAttribute("Email"));
    // 5. Get related rowset of Orders using view link accessor attribute
    RowSet orders = (RowSet)person.getAttribute("Orders");
    // 6. Iterate over the Orders rows
    while (orders.hasNext()) {
        Row order = orders.next();
        // 7. Print out some order attribute values
        System.out.println(" ["+order.getAttribute("OrderStatusCode")+"] "+
                            order.getAttribute("OrderId")+": "+
                            order.getAttribute("OrderTotal"));
        if(!order.getAttribute("OrderStatusCode").equals("COMPLETE")) {
        // 8. Get related rowset of OrderItems using view link accessor attribute
        RowSet items = (RowSet)order.getAttribute("OrderItems");
        // 9. Iterate over the OrderItems rows
        while (items.hasNext()) {
            Row item = items.next();
            // 10. Print out some order items attributes
            System.out.println("  "+item.getAttribute("LineItemId")+": "+
                                item.getAttribute("LineItemTotal"));
            }
        }
        }
    }
    Configuration.releaseRootApplicationModule(am,true);
  }
}

このプログラムを実行すると、例6-10に示す出力が生成されます。

例6-10 TestClient2.javaの実行結果

Staff Member: David Austin
 [Open] 104: Spin cycle not draining
  1: Researching issue
Staff Member: Bruce Ernst
 [Closed] 101: Agitator does not work
 [Pending] 102: Washing Machine does not turn on
  1: Called customer to make sure washer was plugged in...
  2: We should modify the setup instructions to include...
 [Open] 108: Freezer full of frost
  1: Researching issue
Staff Member: Alexander Hunold
 [Closed] 100: I have noticed that every time I do a...
 [Closed] 105: Air in dryer not hot
   :

6.4.8 行の検索および外部キー値の更新の方法

行を検索して外部キーの値を更新するには、次の基本的な手順に従います(例6-11を参照)。

  1. ビュー・オブジェクト・インスタンスを検索します。

  2. Keyオブジェクトを作成し、ビュー・インスタンスの行を参照します。

  3. findByKey()を使用して行を検索します。

  4. 必要に応じて、行の属性を操作します。

例6-11は、外部キーの値を検索して更新し、Ordersビュー・オブジェクト・インスタンスの行を検索するmain()メソッドを示しています。このサンプルでは、行の値が変更される前に、既存のOrderStatusCode属性の値が出力されます。

例6-11 外部キー値の検索および更新

package oracle.fodemo.storefront.client;

import oracle.jbo.ApplicationModule;
import oracle.jbo.JboException;
import oracle.jbo.Key;
import oracle.jbo.Row;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

public class TestFindAndUpdate {
    public static void main(String[] args) {
        String  amDef = 
                    "oracle.fodemo.storefront.store.service.StoreServiceAM";
        String  config = "StoreServiceAMLocal";
        ApplicationModule am =
                    Configuration.createRootApplicationModule(amDef,config);
        // 1. Find the Orders view object instance
        ViewObject vo = am.findViewObject("Orders");
        // 2. Construct a new Key to find Order # 1011
        Key orderKey = new Key(new Object[]{1011});
        // 3. Find the row matching this key        
        Row[] ordersFound = vo.findByKey(orderKey,1);
        if (ordersFound != null && ordersFound.length > 0) {
            Row order = ordersFound[0];
            // 4. Print some order information
            String orderStatus = (String)order.getAttribute("OrderStatusCode");
            System.out.println("Current status is: "+ orderStatus);
            try {
                // 5. Try setting the status to an illegal value
                order.setAttribute("OrderStatusCode","REOPENED");
            }
            catch (JboException ex) {
                System.out.println("ERROR: "+ex.getMessage());
            }
            // 6. Set the status to a legal value
            order.setAttribute("OrderStatusCode","PENDING");
            // 7. Show the value of the status was updated successfully
            System.out.println("Current status is: " +
                        order.getAttribute("OrderStatusCode"));
            // 8. Show the current value of the customer for this order
            System.out.println("Customer: " + order.getAttribute("CustomerId"));
            // 9. Reassign the order to customer # 113
            order.setAttribute("CustomerId",113); // Luis Popp
            // 10. Show the value of the reference information now 
            System.out.println("Customer: "+order.getAttribute("CustomerId"));
            // 11. Rollback the transaction
            am.getTransaction().rollback();
            System.out.println("Transaction canceled");      
        }        Configuration.releaseRootApplicationModule(am,true);
    }  
}

この例を実行すると、例6-12に示す出力が生成されます。

例6-12 TestFindAndUpdate.javaの実行結果

Current status is: Closed
ERROR: The status must be Open, Pending, or Closed
Current status is: Open
Assigned: bernst
Assigned: Luis Popp
Transaction canceled

6.4.9 ビュー・オブジェクト・インスタンスの新しい行の作成方法

新しいビュー行インスタンスを作成するには、次の基本的な手順に従います(例6-13を参照)。

  1. ビュー・オブジェクト・インスタンスを検索します。

  2. 新しい行を作成し、行セットに挿入します。

  3. 新しい行の必須属性の値を設定します。

  4. トランザクションをコミットします。

例6-13は、Ordersビュー・オブジェクト・インスタンスを検索し、新しい行を行セットに挿入するmain()メソッドを示しています。Ordersビュー・オブジェクトはエンティティ・ベースなので、CreatedBy属性は、マップされたエンティティ・オブジェクト属性から値を導出します。このサンプルでは、トランザクションのコミット前に、残りの属性の値が設定されます。

例6-13 新規オーダーの作成

package oracle.fodemo.storefront.client;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;
import oracle.jbo.domain.DBSequence;
import oracle.jbo.domain.Date;
import oracle.jbo.domain.Timestamp;

public class TestCreateOrder {
    public static void main(String[] args) throws Throwable {
        String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM";
        String config = "StoreServiceAMLocal";
        ApplicationModule am = 
                Configuration.createRootApplicationModule(amDef, config);
        // 1. Find the Orders view object instance.
        ViewObject orders = am.findViewObject("Orders");
        // 2. Create a new row and insert it into the row set
        Row newOrder = orders.createRow();
        orders.insertRow(newOrder);
        // Show the entity object-related defaulting for CreatedBy attribute
        System.out.println("CreatedBy defaults to: " + 
                            newOrder.getAttribute("CreatedBy"));
        // 3. Set values for some of the required attributes        
        Date now = new Date(new Timestamp(System.currentTimeMillis()));
        newOrder.setAttribute("OrderDate", now);
        newOrder.setAttribute("OrderStatusCode", "PENDING");
        newOrder.setAttribute("OrderTotal", 500);
        newOrder.setAttribute("CustomerId", 110);
        newOrder.setAttribute("ShipToAddressId", 2);
        newOrder.setAttribute("ShippingOptionId", 2);
        newOrder.setAttribute("FreeShippingFlag", "N");
        newOrder.setAttribute("GiftwrapFlag", "N");
        // 4. Commit the transaction
        am.getTransaction().commit();
        // 5. Retrieve and display the trigger-assigned order id
        DBSequence id = (DBSequence)newOrder.getAttribute("OrderId");
        System.out.println("Thanks, reference number is " + 
                            id.getSequenceNumber());
        Configuration.releaseRootApplicationModule(am, true);
    }
}

この例を実行すると、例6-14に示す結果が生成されます。

例6-14 TestCreateOrder.javaの実行結果

CreatedBy defaults to: Luis Popp
Thanks, reference number is 200

6.4.10 行を識別する行キーの取得方法

行キーを取得して行を特定するには、次の基本的な手順に従います(例6-15を参照)。

  1. ビュー・オブジェクト・インスタンスを検索します。

  2. 指定された値を使用してキーを作成します。

  3. このキーを使用して行を検索します。

  4. 必要に応じて、行のキーを操作します。

例6-15は、Ordersビュー・オブジェクト・インスタンスを検索し、行キーを作成してオーダー番号を検索するmain()メソッドを示しています。findByKey()メソッドでは、指定されたキーによりOrders行を検索します。このサンプルでは、次に行のキーが表示され、OrderItemsビュー・リンク・アクセッサを使用して行セットにアクセスし、行を反復処理して各OrderItems行のキーが表示されます。

例6-15 行を識別する行キーの取得

package oracle.fodemo.storefront.client;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Key;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

public class TestFindAndShowKeys {
    public static void main(String[] args) {
        String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM";
        String config = "StoreServiceAMLocal";
        ApplicationModule am = 
            Configuration.createRootApplicationModule(amDef, config);
        // 1. Find the Orders view object instance
        ViewObject vo = am.findViewObject("Orders");
        // 2. Construct a key to find order number 1011
        Key orderKey = new Key(new Object[] { 1011 });
        // 3. Find the Orders row with the key
        Row[] ordersFound = vo.findByKey(orderKey, 1);
        if (ordersFound != null && ordersFound.length > 0) {
            Row order = ordersFound[0];
            // 4. Displays the key of the Orders row
            showKeyFor(order);
            // 5. Accesses row set of Orders using OrderItems view link accessor
            RowSet items = (RowSet)order.getAttribute("OrderItems");
            // 6. Iterates over the OrderItems row
            while (items.hasNext()) {
                Row itemRow = items.next();
                // 4. Displays the key of each OrderItems row
                showKeyFor(itemRow);
            }
        }
        Configuration.releaseRootApplicationModule(am, true);
    }

    private static void showKeyFor(Row r) {
        // get the key for the row passed in
        Key k = r.getKey();
        // format the key as "(val1,val2)"
        String keyAttrs = formatKeyAttributeNamesAndValues(k);
        // get the serialized string format of the key, too
        String keyStringFmt = r.getKey().toStringFormat(false);
        System.out.println("Key " + keyAttrs + " has string format " + 
                            keyStringFmt);
    }
    // Build up "(val1,val2)" string for key attributes

    private static String formatKeyAttributeNamesAndValues(Key k) {
        StringBuffer sb = new StringBuffer("(");
        int attrsInKey = k.getAttributeCount();
        for (int i = 0; i < attrsInKey; i++) {
            if (i > 0)
                sb.append(",");
                sb.append(k.getAttributeValues()[i]);
        }
        sb.append(")");
        return sb.toString();
    }
}

この例を実行すると、例6-16に示す結果が生成されます。シリアライズされたキーの文字列フォーマットは16進数で、キー内のすべての属性を示す単一文字列に情報が含まれています。

例6-16 TestFindAndShowKeys.javaの実行結果

Key (1011) has string format 000100000003313031
Key (1011,1) has string format 000200000003C2020200000002C102
Key (1011,2) has string format 000200000003C2020200000002C103

6.4.11 テスト・クライアントでのテスト・ユーザー認証方法

アプリケーションに対してADFセキュリティを有効にし、テスト・ユーザーにjazn-data.xmlファイルをプロビジョニングしている場合は、テスト・クライアントを実行する前に、ユーザーを認証するためのメソッド・コールを組み込む必要があります。テスト・クライアントでユーザーを認証するには、次の基本的な手順に従います(例6-17を参照)。

  1. 認証サービスを作成します。

  2. jazn-data.xmlファイルに定義されている、テスト・ユーザー用のログイン資格証明を渡します。

  3. 認証が成功したら、アプリケーション・モジュールをテストします。

  4. ユーザーをログアウトします。

ADFセキュリティの構成ウィザードを実行してADFセキュリティを有効にする方法、およびJDeveloperのアイデンティティ・ストアにテスト・ユーザーを作成する方法の詳細は、30.2項「ADFセキュリティ・プロセスの概要」を参照してください。

例6-17 テスト・クライアントでのログイン資格証明の渡し方

package oracle.summit.model.test;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Key;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;

import oracle.adf.share.security.AuthenticationService;
import oracle.adf.share.security.authentication.AuthenticationServiceUtil;
import oracle.adf.share.ADFContext;
import oracle.adf.share.security.SecurityContext;
import oracle.adf.share.security.SecurityEnv;

import javax.security.auth.Subject;

public class TestAuthenticationClient {
    public static void main(String[] args) {
        String amDef = "test.TestAuthModule";
        String config = "TestAuthModuleLocal";

        // 1. Create authentication service.
        AuthenticationService authService =
                            AuthenticationServiceUtil.getAuthenticationService();
        try
           {
              // 2. Pass in user id and password defined in local identity store.
              authService.login("tester1", "welcome1");
           }
           catch (Exception e)
           {

           }

        // Uncomment to output authentication status
        // String userName = 
                       ADFContext.getCurrent().getSecurityContext().getUserName();

        // System.out.println("*** userName : " + userName);
        // Subject subject = 
                       ADFContext.getCurrent().getSecurityContext().getSubject();
        // System.out.println("Subject : " + subject);

        // 3. Test application module if authentication succeeds.
        if (ADFContext.getCurrent().getSecurityContext().isAuthenticated()) {
           ApplicationModule am = 
                       Configuration.createRootApplicationModule(amDef,config);
           ViewObject vo = am.findViewObject("TestView");
           // Work with your appmodule and view object here
           Configuration.releaseRootApplicationModule(am,true);

           // 4. Log out test user.
           authService.logout();

           // Uncomment to report logout success
           // boolean isAuthenticated = 
                   ADFContext.getCurrent().getSecurityContext().isAuthenticated();
           // System.out.println("*** isAuthenticated : " + isAuthenticated);
        }

    }
}