プライマリ・コンテンツに移動
Oracle® Mobile Application Framework Oracle Mobile Application Frameworkでのモバイル・アプリケーションの開発
2.3.3
E82940-01
目次へ移動
目次

前
次

6 MAFアプリケーションでのクライアント・データ・モデルの作成

この章では、RESTサービスからリソースを取得して、MAFアプリケーションのクライアント・データ・モデルにデータ・オブジェクトおよびサービス・オブジェクトを作成する方法について説明します。

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

6.1 MAFアプリケーションのクライアント・データ・モデルの概要

RESTサービスに接続するMAFアプリケーションは、データ・オブジェクトからデータを取得します。Javaクラス、データ・オブジェクトおよびサービス・オブジェクトは、クライアント・データ・モデルの作成のために使用されます。このモデルでは、MAFアプリケーションがオフラインで使用するためにデータを永続化します。

クライアント・データ・モデルのMAFアプリケーションには、MAFアプリケーションのデータ・モデルを表すためのJavaクラスと関連ファイルが含まれています。MAFでは、オフラインでデータを使用できるようにSQLiteデータベースを使用してデータを格納し、データ・オブジェクト(エンティティ・オブジェクトとも呼ばれます)およびサービス・オブジェクト(エンティティCRUDサービス・オブジェクトとも呼ばれます)という2つのタイプのJavaクラスを使用してデータと対話します。データ・オブジェクトは、MAFアプリケーションの接続先のRESTサービスから取得したデータを保持します。MAFアプリケーションは、デバイス上のSQLiteデータベースに対してデータ・オブジェクトを格納および取得します。サービス・オブジェクトは、作成、読取り、更新、削除(CRUD)アクションに加え、データ・オブジェクトに対して機能する他のカスタム・アクションを実行します。通常、サービス・オブジェクトを使用してデータ・コントロールを作成し、そのデータ・コントロールから関連するメソッドおよびエンティティ・コレクションをAMXページにドラッグ・アンド・ドロップして、UIレイヤーを構築できます。MAFクライアント・データ・モデルでは、persistence-mapping.xmlファイルを使用してオブジェクト関連マッピング情報を格納し、この情報によってデータベースの表および列をデータ・オブジェクトおよびデータ・オブジェクトの属性にマップする方法、さらにデータ・オブジェクトおよびデータ・オブジェクトの属性をRESTレスポンス・ペイロードの属性にマップする方法を識別します。

図6-1は、MAFクライアント・データ・モデルのランタイム・アーキテクチャで、RESTサービスからの部門情報の読取りおよび書込みを行うMAFアプリケーションの特定の実装を参照しています。

図6-1 MAFクライアント・データ・モデルのランタイム・アーキテクチャ

このイメージについては周囲のテキストで説明しています。

図6-1では、サービス・オブジェクト(DepartmentService)はCRUDアクションに加え、Departmentデータ・オブジェクトに対して機能する他のカスタム・アクションも提供しています。

Departmentデータ・オブジェクトには、RESTサービス・リクエストおよびレスポンス・ペイロードの対応する属性にマップされている部門の属性(名前やIDなど)を対象としたgetterメソッドおよびsetterメソッドがあります。SQLiteデータベースのDEPARTMENTS表には、同じデータ・オブジェクト属性にマップされる列があります。persistence-mapping.xmlファイルには、様々な場所(データベース表の列、Javaクラス属性およびRESTペイロード)にある属性間の関係をマップする情報が格納されます。

MAFは、MAFアプリケーションにクライアント・データ・モデルを作成するために使用する数多くのウィザードをJDeveloperに提供します。「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。クライアント・データ・モデルを作成したら、クライアント・データ・モデルのサービス・オブジェクトからデータ・コントロールを生成できます。MAFには他にも、MAFクライアント・データ・モデルが生成するデータ・コントロールおよびデータ・モデルに基づいてMAFアプリケーションにユーザー・インタフェースを生成するウィザード(MAFユーザー・インタフェース・ジェネレータ)があります。「MAFクライアント・データ・モデルに基づくユーザー・インタフェースの作成」を参照してください。

ヒント:

RESTサービスへのアクセスにクライアント・データ・モデルを使用するMAFアプリケーションの作成を順を追って説明するチュートリアルは、Oracle MAFおよびクライアント・データ・モデル(CDM)によるREST/JSONサービスの使用および永続化を参照してください。

6.2 MAFアプリケーションでのクライアント・データ・モデルの作成の概要

RESTサービスからクライアント・データ・モデルを作成するには、データ・オブジェクトを検出し、そのオブジェクトの属性を構成し、それらのリレーションシップをマッピングし、CRUDアクションに使用するRESTリソースを特定し、モデルに組み込むアーティファクトを生成します。

このウィザードを使用すると、汎用的なRESTサービスまたはOracle Mobile Cloud Service (MCS)にホストされているRESTサービスに接続できます。接続すると、アプリケーションで使用するデータを識別して取得するというタスクを実行するためのダイアログがMAFに追加で表示されます。これらのタスクは次のとおりです。

  1. MAFアプリケーションでの使用候補となるデータ・オブジェクトを検出します。MAFでは、次のデータ・オブジェクト・リソースからデータ・オブジェクトを検出できます。

    1. サンプルRESTリソースURL

    2. サンプル・リソース・ペイロード

    3. RAMLファイル

  2. MAFアプリケーションでの使用候補となるデータ・オブジェクトを検出すると、使用するデータ・オブジェクトを選択するためのダイアログがMAFに表示されます。また、MAFには新規データ・オブジェクトを作成するためのオプションが用意されています。

  3. 追加のダイアログでは、データ・オブジェクト属性を確認して変更できます。実行できるタスクには、デバイスに機密データを保持しないようにすることの他に、属性名、RESTサービス・ペイロードに表示される名前、各属性のJavaタイプおよびデータベース列のタイプを編集することなどがあります。また、キー属性を選択します。選択するキー属性が一意であることが重要です。

  4. データ・オブジェクトの親子関係を指定します。

  5. CRUDアクションに使用するRESTリソースおよび関連するHTTPメソッドを定義し、さらには問合せパラメータやパス・パラメータなどのリソース詳細を指定します。

  6. CRUDアクションに使用するRESTリソースを特定したら、MAFアプリケーションの実行時動作を設定するためのダイアログがMAFに表示されます。ここでは、たとえば、オフライン・トランザクションを有効にしたり、バックグラウンドでのリモートの読取りおよび書込みを有効にしたり、Webサービス・エラーを表示します。

  7. MAFに最後に表示されるダイアログでは、MAFがクライアント・データ・モデルのために生成したアーティファクトをアプリケーションのどこに配置するかを指定します。このダイアログを使用して、MAFが生成したJavaクラスのプロジェクトの場所およびパッケージ名を決定します。

「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードを完了すると、MAFがMAFアプリケーションのクライアント・データ・モデルを生成します。ウィザードを再度起動して、生成されたクライアント・データ・モデルを編集できます。たとえば、RESTサービスでデータ・モデルに含める追加のデータ・オブジェクトを特定します。RESTサービスに接続することなく、追加のデータ・オブジェクトを取得するようにクライアント・データ・モデルを編集する場合は、「永続性マッピングの編集」ウィザードを起動します。この後者のウィザードは、「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードとダイアログを共有しますが、RESTサービスへの接続が必要ありません。

また、クライアント・データ・モデルのサービス・オブジェクトからデータ・コントロールを生成することもできます。データ・コントロールを生成したら、データおよび操作を「データ・コントロール」パネルからAMXページにドラッグ・アンド・ドロップして、MAFアプリケーションのUIを作成できます。MAFユーザー・インタフェース・ジェネレータを使用してMAFアプリケーションのプロトタイプUIを生成する場合は、データ・コントロールの作成が前提条件となります。「MAFクライアント・データ・モデルに基づくユーザー・インタフェースの作成」を参照してください。

注意:

MCSでホストされたRESTサービスに接続する場合は、MCS Data Offline & Synchronization APIを使用しないでください。MAFクライアント・データ・モデルにより、MAFアプリケーションはオフラインで動作して、MAFアプリケーションがオンラインに戻ったときにはデータを同期できるようになります。

6.3 RESTサービスへの接続によるクライアント・データ・モデルの作成

RESTサービスに接続して、MAFアプリケーションのクライアント・データ・モデルで使用するために取得するデータ・オブジェクト・リソースを特定します。

(汎用的なサービスかMCSにホストされているサービスかに関係なく) RESTサービスに接続するには、「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードを起動します。次を参照してください。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

6.3.1 RESTサービスに接続してデータ・オブジェクトを取得する方法

「新規ギャラリ」「モバイル・アプリケーション・フレームワーク」「REST WebサービスからのMAFクライアント・データ・モデル」オプションにアクセスして、RESTサービスに接続する手順を使用してください。取得用のRESTサービスでデータ・オブジェクトを検出して、MAFアプリケーションのクライアント・データ・モデルに使用します。

MAFアプリケーション・データ・モデルを作成するには:
  1. MAFアプリケーションの作成「MAFアプリケーションの作成方法」を参照してください。
  2. メイン・メニューで、「ファイル」「ギャラリから」を選択します。
  3. 「新規ギャラリ」の「ビジネス層」カテゴリの「モバイル・アプリケーション・フレームワーク」ノードで、「REST WebサービスからのMAFクライアント・データ・モデル」をダブルクリックします。
  4. 「ようこそ」ページで、「次へ」をクリックします。
  5. 図6-2に示す「接続」ページで、「RESTサービス接続」ドロップダウン・フィールドの横にある緑のプラス・アイコンをクリックしてダイアログを起動し、接続先のRESTサービスに対するURLエンドポイントの接続名を定義します。

    図6-2 REST接続ダイアログ

    このイメージについては周囲のテキストで説明しています。
  6. 接続の名前を入力し、「サービスのベースURI」入力フィールドにRESTサービスのURLエンド・ポイントを指定します。
    利便性のため、URLエンド・ポイントの一部はMAFアプリケーションが使用するすべてのRESTリソースで同じものを指定します。これにより、ウィザードの後続ページで行う必要がある入力の量が削減されます。1つの例外は、MCSのインスタンスへのURLエンド・ポイントを指定する場合です。この後者の場合、URLエンド・ポイントは/mobileで終わる必要があります。これにより、MAFアプリケーションではカスタムAPIコールとMCSプラットフォームAPIコールの両方に接続を使用できます。

    注意:

    図6-2に示すように、URLエンド・ポイントに対して不完全なURLを指定しているため、「接続のテスト」ボタンをクリックしても、ここでは機能しません。URLエンド・ポイントがフォワード・スラッシュで終わっていないことを確認してください(ウィザードでは、これを確認しないと、「次へ」をクリックできるようになりません)。
  7. アクセスするRESTリソースが保護されている場合は、認証情報を該当するフィールドに入力します。
  8. 「OK」をクリックして、「接続」ページに戻り、適切なオプションを選択します。
    • 接続先のRESTサービスがMCSにホストされていない場合は、「次へ」をクリックします。
    • 接続先のRESTサービスがMCSにホストされている場合は、「MCS接続」チェック・ボックスを選択します。「MCSモバイル・バックエンドID」および「MCS無名アクセス・キー」入力フィールドへの入力の詳細は、「MCS無名アクセス・キーに関する必知事項」を参照してください。
RESTサービスに接続すると、MAFアプリケーションのクライアント・データ・モデルに取り込んで使用するためのデータ・オブジェクトをRESTサービスで検出できます。「クライアント・データ・モデルの候補データ・オブジェクトの検出」を参照してください。

6.3.2 MCS無名アクセス・キーに関する必知事項

MAFアプリケーションがMCSで認証される前にMCSにアクセスすると、MAFはMCS無名アクセス・キー値を使用して認可ヘッダーを作成します。これは、たとえば、ユーザーがログインする前にMCSにstartSession MCS分析イベントを送信する場合に便利です。

使用するアクセス・キー値が匿名キーである必要はありません。MCSモバイル・バックエンドのユーザー・レルムに定義されているMCSユーザーの認可キーを使用できます。これは、たとえば、MCS記憶域収集にアクセスする場合や、匿名ユーザーにアクセスできないその他のリソースにアクセスする場合に行います。

アクセス・キーに接頭辞Basicを付ける必要はありません。MAFが必要に応じて接頭辞Basicを追加または削除します。MAFアプリケーションで動的MCS接続をサポートする必要がある場合は、「MCSモバイル・バックエンドID」フィールドおよび「MCS無名アクセス・キー」フィールドにEL式を指定できます。MCSに対して認証されると、MAFがユーザーのログイン資格証明に基づいてすべてのRESTコールに認可ヘッダーを自動的に挿入します。つまり、MAFアプリケーションが認証されたら、MAFは入力フィールドのMCS無名アクセス・キー値を無視します。

6.4 クライアント・データ・モデルの候補データ・オブジェクトの検出

MAFアプリケーションがRESTサービスに接続されると、アプリケーションのクライアント・データ・モデルに使用するデータ・オブジェクトを選択できます。

「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードには、MAFアプリケーションで使用するデータ・オブジェクトを検出するために次のオプションが用意されています。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

6.4.1 RESTリソースURLを使用してデータ・オブジェクトを検出する方法

RESTサービスを起動し、レスポンス・ペイロードの構造に基づいて候補データ・オブジェクトを返すには、HTTPメソッド(通常はGET)を含め1つ以上のRESTリソースを指定します。

図6-3は、ウィザードの「データ・オブジェクト・リソース」ダイアログを示しています。ここで、問い合せるRESTリソースを指定します。

図6-3 データ・オブジェクト・リソースのRESTリソースの問合せ

このイメージについては周囲のテキストで説明しています。

図6-3に示すように、「追加」ボタンおよび「削除」ボタンを使用して、「リソース」リストに入力するRESTリソースのリストを管理します。RESTリソースを起動するために特定のHTTPヘッダーが必要である場合には、「ヘッダーの設定」ボタンを使用してダイアログを起動し、ここでヘッダーとしてキーと値のペアを入力します。たとえば、RESTサービスから返されるペイロードがXMLではなくJSON形式になるようにする場合は、「ヘッダーの設定」をクリックし、表示されたダイアログにキーとしてContent-Type、値としてapplication/jsonを入力します。

「フラット化されたネスト・オブジェクト」チェック・ボックスの使用は、「フラット化されたネスト・データ・オブジェクト・オプションに関する必知事項」を参照してください。

「次へ」をクリックして、RESTサービスを問い合せて、レスポンス・ペイロードの構造に基づいて候補データ・オブジェクトを返す前に、次の点に注意してください。

  • MAFは、RESTサービスから返されたデータのコレクションにある最初のアイテムを調べます。たとえば、従業員のコレクションにある最初の従業員が営業担当者でなく、このため関連付けられたコミッション属性がない場合、従業員の候補データ・オブジェクトにはコミッション属性が含まれません。同様に、RESTサービスから返されたレスポンス・ペイロードが部門および従業員のマスター/ディテール構造である場合は、返された最初の部門に従業員が含まれていることを確認してください。そうでない場合、従業員は子データ・オブジェクトとして識別されません。ウィザードの後半のページでデータ・オブジェクトおよび属性を追加できます。ただし、可能な場合にはこの作業を回避することが最善です。

  • パス・パラメータを中カッコで囲んで入力した場合、「次へ」をクリックすると、パス・パラメータのサンプル値を入力するためのダイアログ(「URIパラメータ値の入力」)が表示されます。図6-3では、employeesListリソースのパス・パラメータとして現在の部門IDを参照する{id}を指定したため、そのダイアログが表示されます。データを返すサンプル値を入力するようにしてください。たとえば、ID値が20の部門に従業員が含まれていない場合、従業員データ・オブジェクトが識別されることはありません。

  • このページで指定するリソースは、アプリケーションに作成して使用する候補データ・オブジェクトを識別するだけです。CRUDアクションに使用する正確なリソースを指定するには、後のページを使用します。ここで入力する値は、ウィザードの後半にある「CRUDリソース」ページで各データ・オブジェクトの「すべてのリソースの検索」入力フィールドのデフォルト値として使用されるだけです。様々なリソースを使用してデータ・オブジェクトおよび「すべてのリソースの検索」を検出するという状況では、「すべてのリソースの検索」値は使用可能な属性のサブセットを返します。たとえば、従業員の「すべてのリソースの検索」の場合、リスト・ビューに属性(employeeId、firstNameおよびlastName)が返されます。エンド・ユーザーがリスト・ビューの従業員をクリックして詳細画面に移動すると、MAFアプリケーションは選択された従業員のすべての属性を返す正規従業員RESTリソースを起動して、追加の従業員属性をロードします。これにより、データ・セットの規模が大きく各データ・オブジェクトに多数の属性が含まれているときのパフォーマンスが最適化されます。このようなシナリオでは、「データ・オブジェクト・リソース」ウィザード・ページですべての従業員属性を識別する正規RESTリソースを指定します。

6.4.2 サンプルのペイロードを使用してデータ・オブジェクトを検出する方法

候補データ・オブジェクトおよび属性を作成するためのサンプルのペイロードを指定します。

このオプションは、次の場合に便利です。

  • RESTサービスの起動によって返されたデータ・コレクションの最初のアイテムで一部の属性や子データが欠けている場合

  • バックエンド開発チームが作業を続けているため、RESTリソースがまだ使用できない場合

  • アプリケーションでデータの取得は行わず、新規データの作成(ポスト)のみを行う場合。つまり、解析するレスポンス・ペイロードを返すGETリソースがありません。この場合、新規データを作成するときにRESTコールで送信するすべての属性が含まれているサンプルのペイロードを指定します。新規データを作成するためのRESTコールの完全なシグネチャは、ウィザードの後で指定できます。

サンプルのペイロードを指定すると、入力したRESTリソースは起動されません。そのかわり、データ・オブジェクトのデフォルト名、およびウィザードの後半の「CRUDリソース」ページにある「すべてのリソースの検索」値のデフォルト値が導出されます。

図6-4は、「サンプル戻りペイロード」ダイアログを示しています。ここで、サンプルのペイロードを入力します。このダイアログを起動するには、「ペイロード」列内をクリックします。

図6-4 サンプルのペイロードを使用した候補データ・オブジェクトの検出

このイメージについては周囲のテキストで説明しています。

「OK」をクリックして「データ・オブジェクト・リソース」ダイアログに戻り、「次へ」をクリックしてウィザードの次ページに進みます。

6.4.3 RAMLファイルを使用してデータ・オブジェクトを検出する方法

RESTful API Modeling Language (RAML)ファイルを指定して、そのRAMLファイルでの説明に基づいて候補データ・オブジェクトおよび属性を作成します。

MAFでは、RAMLファイルの内容に基づいてデータ・オブジェクト、親子関係およびCRUDリソースをお薦めしています。つまり、ウィザードの後続のページでは、RAMLファイルの内容に基づいてデフォルト値が表示されます。

図6-5 RAMLファイルを使用した候補データ・オブジェクトの検出

このイメージについては周囲のテキストで説明しています

RESTリソースを起動するために特定のHTTPヘッダーが必要である場合には、「ヘッダーの設定」ボタンを使用してダイアログを起動し、ここでヘッダーとしてキーと値のペアを入力します。たとえば、RESTサービスから返されるペイロードがXMLではなくJSON形式になるようにする場合は、「ヘッダーの設定」をクリックし、表示されたダイアログにキーとしてContent-Type、値としてapplication/jsonを入力します。

「フラット化されたネスト・オブジェクト」チェック・ボックスの使用は、「フラット化されたネスト・データ・オブジェクト・オプションに関する必知事項」を参照してください。

6.4.4 フラット化されたネスト・データ・オブジェクト・オプションに関する必知事項

JSONペイロードが次のようになっているときは、フラット化されたネスト・データ・オブジェクト・チェック・ボックスを選択します。ここでは、独自のデータ・オブジェクトとしてデフォルトでmanagerを作成します。フラット化されたネスト・データ・オブジェクト・チェック・ボックスを選択すると、departmentデータ・オブジェクト内にmanagerの2つの属性(nameおよびemail)が含まれます。

[
{
"departmentId" : 10,
"departmentName" :"Administration",
"locationId" : 1700,
"manager": {"name" :"Steven"
            "email"  : "steven@oracle.com"  
           }
}
, ...
]

6.4.5 ADF BC REST記述を使用してデータ・オブジェクトを検出する方法

URIを指定して、ADFビジネス・コンポーネントによって公開されたRESTサービスを起動します。

Oracle ADFビジネス・コンポーネントでは、一連のビュー・オブジェクトを公開するアプリケーション・モジュールの上で機能する、REST APIの公開がサポートされています。/describeリソースは、このタイプのREST APIを作成すると自動的に含まれます。『Oracle Application Development FrameworkによるFusion Webアプリケーションの開発』のアプリケーション・モジュールを使用したRESTful Webサービスの作成に関する項を参照してください。

/describeリソースを含むURIへのMAFアプリケーション・リクエストは、RESTリソースを記述するメタデータを返します。このウィザードでは、そのメタデータを調べ、この検査に基づいてウィザードの後半でデータ・オブジェクトおよびRESTリソース・ページを移入します。

図6-6 ADFビジネス・コンポーネント記述の使用による候補データ・オブジェクトの検出

このイメージについては周囲のテキストで説明しています。

6.5 クライアント・データ・モデルのデータ・オブジェクトの選択および永続化

MAFが識別する候補データ・オブジェクトのリストから、MAFアプリケーションのクライアント・データ・モデルで使用するデータ・オブジェクトを選択します。また、オフラインのときにMAFアプリケーションがデータ・オブジェクトのインスタンスにアクセスできるように、永続化するデータ・オブジェクトを選択します。

「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードのデータ・オブジェクトの選択ページおよび「データ・オブジェクト属性」ページでは、次のタスクを実行できます。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

6.5.1 データ・オブジェクトを選択および永続化する方法

含めるデータ・オブジェクトを選択し、不要なデータ・オブジェクトのチェック・ボックスの選択を解除します。MAFがクライアント・データ・モデルを作成するときに有効なJavaクラス名を生成するように、「クラス名」列のデータ・オブジェクトの値を変更します。

MAFアプリケーションがオフライン・モードでデータにアクセスできるように、データを永続化するデータ・オブジェクトごとに「永続」チェック・ボックスを選択します。これにより、MAFはデータ・オブジェクトのSQLiteデータベース表を作成し、ここにはデータを取得するために後で指定するRESTリソースに基づいて実行時にデータが移入されます。

注意:

データが揮発性であるなどの理由で、オフライン・アクセス用にデータ・オブジェクトを永続化しないようにする場合でも、引き続きオフライン・トランザクションにMAFクライアント・データ・モデルを使用できます。トランザクションは別個のDATA_SYNCH_ACTIONS表に格納され、同期はデータ・オブジェクト表から独立しています。

図6-7に示すように、データ・オブジェクトの選択ページに表示される候補データ・オブジェクトのリストの正確性は、候補データ・オブジェクトの検出に使用する方法によって異なります。たとえば、RAMLファイルに基づいて提案されるデータ・オブジェクトのリストは通常、次のようなサンプルのRESTリソースから返されるリストよりも正確です。

[
  {
    "departmentId": 10,
    "departmentName": "Administration",
    "locationId": 1700,
    "_relationships": [
      {
        "_link": {
          "href": "http://localhost:7101/HRRest/persistence/v1.0/Model-1/entity/Department/10/employees1",
          "rel": "employees1"
        }
      },
      {
        "_link": {
          "href": "http://localhost:7101/HRRest/persistence/v1.0/Model-1/entity/Department/10/employeesList1",
          "rel": "employeesList1"
        }
      }
    ],
    "employeesList1": [
      {
        "_link": {
          "href": "http://localhost:7101/HRRest/persistence/v1.0/Model-1/entity/Employee/200",
          "method": "GET",
          "rel": "self"
        }
      }
    ]
  },

図6-7に示すように、前述のサンプルのRESTリソースはペイロードに含まれているリンク情報の候補データ・オブジェクトを示しています。データ・モデルにリンクに関する情報を含める可能性はほとんどないため、これらの候補データ・オブジェクトでは「選択」列のチェック・ボックスの選択を解除します。また、有効なJavaクラス名が表示されるように、「クラス名」の値を編集します。

図6-7 RESTリソースから取得された候補データ・オブジェクト

このイメージについては周囲のテキストで説明しています

6.5.2 新しいデータ・オブジェクトを作成する方法

モバイル・デバイスにのみ存在し、かつMAFアプリケーションが接続するREST Webサービスによってデータが移入されないデータ・オブジェクトを作成します。

データ・オブジェクトの選択ページの「追加」ボタンをクリックして、データ・モデルに新しいデータ・オブジェクトを追加します。デフォルトで生成される名前(NewDataObject)を一意の有効なJavaクラスに編集します。

MAFは、追加するデータ・オブジェクトごとにSQLiteデータベースにデータベース表を作成します。これらのデータベース表にデータを移入するには、ウィザードを完了するとMAFがデータ・オブジェクト用に生成するサービス・オブジェクトからCRUD操作を使用します。

6.5.3 データ・オブジェクト属性を変更する方法

MAFアプリケーションのクライアント・データ・モデルに含めるために選択したデータ・オブジェクトの属性を選択または変更します。

必要に応じて各属性のキー、必須、属性名、ペイロード内の名前、Javaタイプおよびデータベース列のタイプを設定または変更できます。機密データを保持する属性の場合、永続化しないようにすることもできます。これにより、アプリケーションがオフライン・モードで実行されるときには、属性値がnullになります。

キー属性が一意であることが重要です。永続性ランタイムは、選択したキー属性に基づいてデータ・オブジェクト・キャッシュを使用します。同じキーのデータ・オブジェクト・インスタンスが複数ある場合、それらはすべて同じデータベース表の行に書き込まれます。このため、1つのインスタンス(最後に処理されたインスタンスの属性を保持)のみがMAFアプリケーションのUIに表示されます。つまり、MAFではそれが同じインスタンスとみなされるため、すべてのインスタンスが1つにマージされます。子データ・オブジェクトの場合、親への参照属性がキーの一部になる場合があります。ペイロードにこのような参照属性が含まれていない場合は、それらをウィザードの「親子アクセサ」ページで作成できます。次に、このページ(「データ・オブジェクト属性」)に戻り、キー属性として親移入属性を選択します。

サンプルのリソースを使用して候補データ・オブジェクトを特定するときは、一般に属性のJavaタイプがjava.lang.Stringと表示されるため、通常それらを変更する必要があります。属性によっては、ペイロード値を二重引用符で囲まないと、java.math.BigDecimalと表示されることがあります。クラス・ピッカーを使用してJavaタイプを変更でき、選択したJavaタイプに基づいてデータベース列のタイプが自動的に更新されます。通常のタイプ変更では、数値属性をStringまたはBigDecimalからLongまたはIntegerに変更します。日付属性をjava.util.Dateに設定し、日付書式をJSONペイロードで使用するように指定する必要があります(たとえば、yyyy-MM-dd'T'HH:mm:ssZ)。ウィザードの後でアクセスする「CRUDリソース」ページの「ペイロード日付書式」フィールドに日付書式を指定します。

RAMLファイルを使用してデータ・オブジェクトを検出した場合は、通常デフォルトの属性タイプが適切であり、変更する必要はありません。

注意:

「データ・オブジェクト」ドロップダウン・リストから各データ・オブジェクトを選択して、オブジェクトの属性に必要な変更を加えます。

図6-8 データ・オブジェクト属性の変更

このイメージについては周囲のテキストで説明しています。

6.6 データ・オブジェクトの親子関係の指定

マスター/ディテール画面をレンダリングするためのMAFアプリケーションのUIが必要になるデータ・オブジェクトの親子関係を指定します。

図6-9は、このような関係を定義している「親子アクセサ」ページを示しています。部門と部門の従業員との間に存在するような関係を設定するときは、このダイアログを使用します。

図6-9 「親子アクセサ」ページ

このイメージについては周囲のテキストで説明しています。

同じペイロードで親および子データ・オブジェクトを返すRESTリソースを指定し、両方のデータ・オブジェクトを選択したときは、「アクセサ」ドロップダウン・リストに親子関係が移入されます。これは、RAMLファイルを使用してRESTリソースにアクセスした場合にも発生します。ただし、別個のRESTコールで子データ・オブジェクトを取得し、その子オブジェクトが親データ・オブジェクトのペイロードに含まれていない場合、「アクセサ」ドロップダウン・リストは空になります。このシナリオが発生した場合には、「データ・オブジェクトの親子関係を指定する方法」の説明に従って、「親子アクセサ」ページに親子関係を手動で定義します。

MAFが「親子アクセサ」ページに自動的に値を入力したのか、親子関係を手動で定義したのかに関係なく、親子関係ごとに属性マッピングを指定する必要があります。これを行うと、アプリケーションがオフライン・モードで実行されているときにMAFが1対多関係または1対1関係を復元します。データベースの観点から、基になる親と子のデータ・オブジェクト表間に外部キー関係を設定します。図6-9は、departmentIDおよびdepartmentDepartmentIdを指定した例であり、「追加」ボタンを使用して「親子アクセサ」ページの下部にあるリストに両方の属性を追加しています。

子データ・オブジェクトにレスポンス・ペイロードにある外部キー属性が含まれている場合は、「親属性の選択」リストで親キー属性を選択し、「子属性の選択」リストで子データ・オブジェクト外部キー属性を選択し、「追加」をクリックして属性マッピングを追加します。ただし、この外部キー属性は、ペイロードに含まれなかったために子データ・オブジェクトに存在しない場合があります。これは通常、子データ・オブジェクトが親データ・オブジェクト・ペイロード内に入れ子になるために発生します。このシナリオでは、値がペイロードの階層的性質によって推定されるため、外部キー属性を含める必要はありません。MAFでは、オフライン・モード用に引き続き属性マッピングが必要であるため、一致する子属性を選択しなくても、親属性を選択し、「追加」ボタンをクリックできます。前述の図6-9は、このようなユースケースを示しており、「親属性の選択」リストでdepartmentIDを選択し、「追加」ボタンをクリックしています。これで、departmentDepartmentId属性が従業員データ・オブジェクト(および基礎となるデータベース表の列)に追加されます。この属性は部門の従業員詳細を問い合せるときにはRESTペイロードに含まれませんが、実行時のコードが従業員詳細の取得対象である部門インスタンスに基づいてこの属性(および基礎となる列値)を移入します。

ヒント:

この親移入属性の名前は、選択した親属性名が接尾辞として付いたデータ・オブジェクトの名前です。これらの属性名をクリーンな属性名になるように変更できます。前述の例では、「戻る」ボタンをクリックしてこれを行い、部門データ・オブジェクトを選択し、departmentDepartmentId属性の名前をdepartmentIdに変更しています。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

6.6.1 データ・オブジェクトの親子関係を指定する方法

「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードから「親子アクセサ」ページにアクセスします。

データ・オブジェクトの親子関係を指定するには:

  1. 「親子アクセサ」ページで、図6-10に示したプラス・アイコンをクリックし、表示されたダイアログのフィールドに値を入力します。

    たとえば、図6-10に示したダイアログでは、ある部門のすべての従業員を取得する親子アクセサを定義しています。

    図6-10 「親子アクセサ」ページ

    このイメージについては周囲のテキストで説明しています

    注意:

    MAFは、「データ・オブジェクト・リソース」ページで候補データ・オブジェクトの特定に使用したリソースを「子アクセサ・リソース」フィールドに移入します。この例では、これは/entity/Department/{id}/employeesList1です。「子アクセサ属性」フィールドの値は、employeesに設定されています。ウィザードが完了すると、getEmployeesメソッドがdepartmentデータ・オブジェクトに生成され、従業員コレクションが後で作成するデータ・コントロールの部門ノードの下に表示されます。

6.7 CRUD RESTリソースの定義

CRUDアクションを定義すると、MAFアプリケーションのエンド・ユーザーはMAFアプリケーションが接続先のRESTサービスから取得したデータ・オブジェクトを編集できるようになります。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

MAFには「CRUDリソース」ページが用意されており、ここではMAFアプリケーションのクライアント・データ・モデルで使用するために取得したデータ・オブジェクトに対してどのアクションを実行するかを指定します。図6-11は、Departmentsデータ・オブジェクトに対して作成、更新、削除など数多くの操作を指定しているページを示しています。

図6-11 クライアント・データ・モデルのCRUD RESTリソースの定義

このイメージについては周囲のテキストで説明しています。

MAFは、以前に入力した値および候補データ・オブジェクトを検出するために使用した方法に応じて、「CRUDリソース」ページに値を移入します。たとえば、RAMLファイルを使用した場合、次のように、MAFはRESTのベスト・プラクティス規則に基づいてページに値を移入します。

  • POSTリソースがリソースを作成します。

  • PUTリソースまたはPATCHリソースがリソースを更新またはマージします。

  • DELETEリソースがリソースを削除します。

サンプルのリソースURLを使用してデータ・オブジェクトを検出した場合、「すべてのリソースの検索」はデフォルトでサンプルのリソースに設定されます。通常はこのデフォルトが適切ですが、RESTサービスがベスト・プラクティスに従っていない場合には、リソースやHTTPメソッドの値の変更が必要になることがあります。

「データ・オブジェクト」ドロップダウン・リストから各データ・オブジェクトを選択し、次のように入力フィールドに値を入力します。

  • リソースのクイック検索: 大規模なデータ・セットに有用です。大規模なデータ・セットの場合、アプリケーションがメモリーを使い果たしてしまう可能性があるため、通常はすべてのインスタンスを返す「すべてのリソースの検索」を実行しないようにします。そのような状況では、検索基準に一致するインスタンスのみを返すクイック検索機能をユーザー・インタフェースに定義します。小規模なデータ・セットの場合は、「すべてのリソースの検索」を使用して一度にすべてのインスタンスを返します。オンデバイスSQLiteデータベースに対して直接クイック検索フィルタを実行します。Webサービスが起動されないため、パフォーマンスは高速です。

  • 正規リソース: データ・オブジェクトに数多くの属性があり、リストから特定のデータ・オブジェクト・インスタンスを選択したときにのみそのすべての属性を取り込むようにする場合は、正規リソースの値を指定します。

  • 正規トリガー属性: 「正規トリガー属性」を指定した場合、MAFはgetterメソッドで属性の値を取得するときに正規RESTリソースを自動的に起動するコードをデータ・オブジェクト・クラスに生成します。

    たとえば、Departmentデータ・オブジェクトの「すべてのリソースの検索」を選択するとリスト・ページに表示される部門IDと名前のリストが返され、departmentを選択すると詳細ページに移動してすべての部門属性が表示されるようにする場合、「正規トリガー属性」をlocationIdに設定できます。詳細ページに移動すると、getLocationIdメソッドが起動します。MAFは、正規RESTリソースを自動的に起動するためのコードをgetLocationIdメソッド内に生成済です。

  • CRUDリソース(「リソースの作成」「リソースの更新」など): このページで少なくとも1つのRESTリソースが指定されたデータ・オブジェクトごとに生成されるサービス・オブジェクトには、save[DataObjectName]メソッドが含まれています。save[DataObjectName]メソッドを、たとえば「データ・コントロール」パネルからドラッグ・アンド・ドロップすることで起動すると、MAFはデータ・オブジェクト状態に基づいて、コールするリソース(CreateUpdateまたはMerge)を決定します。MAFは、次のように、その決定を下します。

    • データ・オブジェクト状態がnewの場合、MAFはCreateリソースをコールします。Createリソースが指定されていない場合、MAFはMergeリソースをコールします。いずれのリソースも指定されていない場合、MAFアプリケーションはRESTコールを行いません。

    • データ・オブジェクト状態がnewでない場合、MAFはMergeリソースをコールします。Mergeリソースが指定されていない場合、MAFはUpdateリソースをコールします。いずれのリソースも指定されていない場合、MAFアプリケーションはRESTコールを行いません。データ・コントロールCreate操作で新しいデータ・オブジェクトを作成すると、データ・オブジェクト状態はNewに自動的に設定されます。oracle.maf.api.cdm.persistence.model.Entityのサブクラスを使用してプログラムにより新しいデータ・オブジェクト・インスタンスを作成する場合は、setIsNewEntity(true)をコールします。

  • ソート順序: 属性名のカンマ区切りリストを定義します。属性名に接頭辞としてdescを付けると、属性を降順にすることができます。ここに指定したソート順序がユーザー・インタフェースでのデフォルトの順序になることに注意してください。永続性実行時コードでは、ソート順序を実行時に変更するためのUIコントロールを簡単に追加できます。

  • ペイロード日付書式: ペイロード内の日付属性文字列値をjava.util.Dateインスタンスに変換するためのJava日付パターンを指定します。

6.8 CRUD RESTリソース詳細の指定

MAFアプリケーションに定義した様々なRESTリソースの問合せパラメータおよびパス・パラメータとそれらの値などリソース詳細を指定します。

MAFにはCRUDリソース詳細ページが用意されており、ここでリソース詳細を指定します。このウィザード・ページでは、フィールドにデフォルト値を移入します。これらのデフォルトが特定のアプリケーションで意味のあるものになっているかどうかをチェックするようにすると効果的です。図6-12は、このページを示しています。「リソース」ドロップダウンから、レビューまたはカスタマイズする追加のリソースを選択します。また、「リソース」ドロップダウン・メニューの横にあるプラス・アイコンをクリックして、カスタム・リソースを追加することもできます。詳細は、「カスタム・リソースの定義」を参照してください。

図6-12 CRUD RESTリソース詳細の指定

このイメージについては周囲のテキストで説明しています

このページのオプションを理解するには、GET (読取り)リソースとGET以外(書込み)リソースを区別します。フィールドの中には、ある種のリソースにのみ適用されるものや、リソースのタイプに応じて意味が異なるものがあります。

「リソースの詳細」ページでは、次のタスクを実行できます。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

6.8.1 GET (読取り)リソース詳細を指定する方法

GETリソース詳細を指定するには、次のメニュー・オプションを構成します。

  • このRESTリソースを実行する前に、SQLite DB内のローカル行を削除しますか。

    「ローカル行の削除」チェック・ボックスを選択し、GETリソースを「すべてのリソースの検索」として使用している場合、RESTコールの実行後かつRESTレスポンスの処理前に、対応するデータ・オブジェクト用に作成された表のすべての行が削除されます。これは、GETレスポンス・ペイロードに含まれなくなる廃止された行が単に以前にダウンロードされたという理由でアプリケーションに表示されたままにならないようにする場合に便利です。「ローカル行の削除」チェック・ボックスを選択し、子データ・オブジェクトを取得するために「親子アクセサ」ダイアログでGETリソースを定義していた場合、RESTコールの実行直前にそのすべての子行が削除されます。

  • ペイロード・リスト要素名

    「ペイロード・リスト要素名」は、レスポンス・ペイロード内のリソース・データ・オブジェクトを表すJSONオブジェクトの実際の配列を探す方法をMAFに指示します。たとえば、レスポンス・ペイロードが次のようになっているとします。

    {"departmentList":[{"departmentId":10, "departmentName": "Accounting", "locationId": 1400, "managerId": 103}, {"departmentId":20, "departmentName": 
                                                                                                      "Marketing", "locationId": 1400, "managerId": 102} ]}

    この場合、「ペイロード・リスト要素名」をdepartmentListに設定する必要があります。departmentListは、トップレベルのJSONオブジェクト属性である必要はないことに注意してください。MAFは、この属性名のオブジェクトを見つけるまで、レスポンス・オブジェクト・ツリーを再帰的に移動します。レスポンス・ペイロードが直接必要な配列で始まる場合には、このフィールドを空白のままにすることができます。

  • ペイロード行要素名

    「ペイロード行要素名」フィールドを使用すると、特定の配列インスタンス内で適切なJSONオブジェクトを探す方法をMAFに指示できます。たとえば、レスポンス・ペイロードが次のようになっているとします。

    {"departmentList":["department":{"departmentId":10, "departmentName": "Accounting", "locationId": 1400, "managerId": 103}}, "department":{"departmentId":20, 
                                                                                             "departmentName": "Marketing", "locationId": 1400, "managerId": 102}) ]}

    「ペイロード行要素名」をdepartmentに設定してください。MAFが解析する実際のJSONオブジェクトに到達するために深く入れ子になったオブジェクト・ツリーを移動する必要がある場合、このフィールドではドット表記を使用します。たとえば、departmentTopObject.departmentとします。

6.8.2 GET以外(書込み)リソース詳細を指定する方法

GET以外リソース詳細を指定するには、次のメニュー・オプションを構成します。

  • シリアライズ・データ・オブジェクトをペイロードとして送信

    「シリアライズ・データ・オブジェクトをペイロードとして送信」チェック・ボックスは通常、PUT、POST、PATCHのいずれかのリクエストを行うときに選択します。サーバー側での削除の実装方法によっては、DELETEリクエストでも選択する場合があります。このチェック・ボックスを選択すると、「データ・オブジェクト属性を変更する方法」で説明しているように、MAFは「データ・オブジェクト属性」ページで「ペイロード内の名前」プロパティが設定されているデータ・オブジェクト属性ごとにキーと値のペアでリクエスト・ペイロードを作成します。

    {"departmentId":10, "departmentName": "Accounting", "locationId": 1400, "managerId": 103}
  • 配列として送信

    「配列として送信」チェック・ボックスは、次の例に示すように、キーと値のペアを保持するJSONオブジェクトをカッコで囲む場合に選択します。「シリアライズ・データ・オブジェクトをペイロードとして送信」チェック・ボックスを選択するまで、このチェック・ボックスは無効になっています。

     [{"departmentId":10, "departmentName": "Accounting", "locationId": 1400, "managerId": 103}]
  • ペイロード行要素名

    キーと値のペアを持つ実際のJSONオブジェクトを別のオブジェクト内に入れ子にするようにMAFに指示するために使用します。たとえば、リクエスト・ペイロードが次のようになっているとします。

    {"department":{"departmentId":10, "departmentName": "Accounting", "locationId": 1400, "managerId": 103}}

    この場合、「ペイロード行要素名」departmentに設定する必要があります。

    GETリソースとは異なるペイロード属性名がリクエスト・ペイロードで必要になる場合は、これらの書込み固有のペイロード属性名をここに指定することはできません。RestJSONPersistenceManagerをサブクラス化し、getPayloadKeyValuePairsメソッドをオーバーライドする独自のリモート永続性マネージャを作成する必要があります。カスタムのリモート永続性マネージャは、ウィザードの次ページで登録することも、後で登録することもできます。「MAFアプリケーションでのクライアント・データ・モデルの編集」を参照してください。

  • 除外する属性

    リクエスト・ペイロードとして使用されるJSONオブジェクトにシリアライズしない属性名のカンマ区切りリストを指定します。たとえば、departmentIdを指定した場合、次のペイロードはそれをJSONオブジェクトへのシリアライズから除外します。

    {"departmentName": "Accounting", "locationId": 1400, "managerId": 103}

    「データ・オブジェクト属性」ページで「ペイロード内の名前」フィールドの値を無効にすることで同じことを実現できますが、その場合GETリクエストでdepartmentIdも無視されることになり、これは通常望ましいことではありません。このフィールドでは、データ・オブジェクト属性のペイロード名ではなく、これらの属性の名前を使用する必要があります。

6.8.3 カスタム・リソースを追加する方法

カスタム・リソースは、「CRUDリソース」ページで指定した検索、作成、更新、削除のいずれのアクションにもマップしない独自のRESTコールです。

「リソースの詳細」ページでカスタム・リソースを追加できます。図6-13に示すように、緑のプラス・アイコンをクリックして「新規カスタム・リソース」ダイアログを起動し、ここでカスタム・リソースを定義できます。

図6-13 カスタム・リソースの追加

このイメージについては周囲のテキストで説明しています

MAFがデータ・オブジェクト用に生成するサービス・クラスでは、「名前」フィールドに指定した名前でメソッドが追加されます。このメソッドをコールすると、RESTリソースが起動します。MAFクライアント・データ・モデルのデータ同期メカニズムにはカスタム・メソッドも含まれているため、オフライン・モードでカスタム・メソッドをコールした場合、それは保留中の同期アクションとして登録され、RESTコールはMAFアプリケーションが再度オンラインになったときに実行されます。

6.8.4 問合せパラメータおよびパス・パラメータを指定する方法

「CRUDリソース」ページまたは「親子アクセサ」ダイアログのRESTリソースに指定したカッコで囲まれたパス・パラメータが、デフォルトで「パラメータ」リストに表示されます。

追加の問合せパラメータを追加するには、「追加」ボタンを使用します。

図6-14 問合せパラメータおよびパス・パラメータの指定

このイメージについては周囲のテキストで説明しています。

MAFアプリケーションは、RESTリソースを実行するときに、選択された値プロバイダに基づいてリソース問合せパラメータ値およびパス・パラメータ値を自動的に移入します。

  • DataObjectAttribute: データ・オブジェクト属性の値をパラメータに移入します。この値プロバイダを使用するときは、「データ・オブジェクト属性」ドロップダウン・リストから値を選択する必要があります。属性がドロップダウン・リストに表示されるデータ・オブジェクトは、リソースの使用状況によって決まります。たとえば、上のリソースは部門内の従業員を返すため、従業員リストのコンテキストを設定するための属性を部門データ・オブジェクトから選択するものと想定しています。

  • SerializedDataObject: 保持する必要があるデータをリクエスト本文ではなく問合せパラメータで送信する場合は、この設定を選択します。この値プロバイダの場合、他の列は空のままにしてください。

  • LiteralValue: 「値」列に指定されているリテラル値をパラメータに移入します。

  • ELExpression: EL式の評価によって取得された値をパラメータに移入します。「値」列にEL式を指定します。EL式は任意のスコープ(applicationScope、pageFlowScope、viewScope、deviceScope、preferenceScope)で使用できますが、式をRESTサービス・コールの実行コンテキストで有効にすることは自己責任です。オフライン・モードでトランザクションを作成した場合、RESTサービスは後で起動され、EL式コンテキストはデータ同期をトリガーするタスク・フローおよびページによって決定されることに注意してください。

  • SearchValue: ユーザー・インタフェースで入力されたクイック検索値の値をパラメータに移入します。通常は、「CRUD RESTリソースの定義」で説明するように、「CRUDリソース」ページに定義している「リソースのクイック検索」でのみこの値プロバイダを使用します。

6.8.5 HTTPヘッダー・パラメータを追加する方法

オブジェクト・リソースの検出ページに指定したHTTPヘッダーは、デフォルトではこれまでに指定したすべてのリソースに適用されます。

ヘッダーを削除する場合やあるリソースに固有の別のヘッダーを追加する場合は、「ヘッダーの設定」ボタンをクリックしてダイアログを起動します。ここでヘッダーのキーと値のペアを入力するか、HTTPヘッダー・パラメータの変更が必要な場合には変更します。

図6-15 HTTPヘッダー・パラメータの設定

このイメージについては周囲のテキストで説明しています

6.9 クライアント・データ・モデルのランタイム・オプションの設定

このウィザードの完了時に生成するMAFアプリケーションのランタイム・オプションを設定します。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

図6-16は、生成されたMAFアプリケーションの実行時の動作を決定する「ランタイム・オプション」ページを示しています。

図6-16 MAFアプリケーションのランタイム・オプションの設定

このイメージについては周囲のテキストで説明しています。

図6-16に表示されるフィールドは、次のように構成します。

  • バックグラウンドでのリモート読取り: 選択した場合、データ・オブジェクトに対して指定されているGETリクエスト(通常、Find All、Find、Canonicalのいずれかのリソース)がバックグラウンド・スレッドで実行されます。MAFアプリケーションのパフォーマンスに対するエンド・ユーザーの認識が高まるため、このチェック・ボックスを選択することをお薦めします。MAFは、まずSQLiteデータベースに問い合せて、これらの結果を画面にただちに表示します(「データ・オブジェクトを選択および永続化する方法」で説明しているように、データ・オブジェクトを永続化したものとします)。RESTコールは、ユーザー・インタフェースをブロックすることなくバックグラウンドで行われます。MAFアプリケーションは、RESTレスポンスを受信すると、ユーザー・インタフェースを自動的に更新します。

  • バックグラウンドでのリモート書込み: 選択した場合、このデータ・オブジェクトに対して指定されているGET以外リクエスト(通常、Create、Update、Mergeのいずれかのリソース)がバックグラウンド・スレッドで実行されます。MAFアプリケーションのパフォーマンスに対するエンド・ユーザーの認識が高まるため、通常このチェック・ボックスは選択したままにします。RESTコールをたとえば「保存」ボタンによってトリガーした後も、エンド・ユーザーはアプリケーションを引き続き使用できます。RESTコールが存続するかぎり、ユーザー・インタフェースはブロックされません。また、RESTレスポンスに含まれている属性の中にサーバー側で値が更新されたものがある場合にも、MAFアプリケーションはユーザー・インタフェースを自動的にリフレッシュします。

  • 自動問合せ: 選択した場合、MAFはデータ・オブジェクトのサービス・オブジェクト・クラスが初期化されるときに、「すべてのリソースの検索」によって指定されたすべての行やコール・リソースをオンデバイス・データベースに自動的に問い合せます。これは、サービス・オブジェクト・クラス用に作成したBeanデータ・コントロールを使用してAMXページを構築するときに便利です。Beanデータ・コントロールは、たとえばリスト・ビューまたはフォーム・ビューを作成するために、AMXページにドラッグ・アンド・ドロップできるコレクション要素を公開します。自動問合せを選択している場合、このコレクション要素はすべてのデータ・オブジェクトを返します。初期状態では、「すべてのリソースの検索」の実行完了後に、SQLiteデータベースに存在するものを返し、リモート・コレクションでリフレッシュされます。このチェック・ボックスの選択を解除した場合は、AMXページに移動する前に、タスク・フローでfinderメソッドを実行する必要があります。そうしないと、AMXページにはデータが表示されません。

  • 「主キーの生成」: 選択した場合、新しいデータ・オブジェクトがSQLiteデータベースに挿入されたものの、主キー属性値がまだnullのときに、MAFアプリケーションは主キーを自動的に生成します。この機能は、主キー属性が数値属性であるときにのみ動作します。MAFは、現在の最大値をSQLiteデータベースに問い合せて、この値を1だけ増加します。

  • オフライン・トランザクションの有効化: 選択した場合、MAFアプリケーションがオフラインのときに、書込みRESTコールを起動できます。MAFは、トランザクション(作成、更新、削除またはカスタムのアクション)を保留中のデータ同期アクションとして登録します。MAFアプリケーションがオンラインになると、MAFはこれらのアクションを同期し、関連付けられたRESTコールを実行します。MAFアプリケーションがオンラインで、RESTリソースを起動するときにサーバーが使用できないか、またはサーバーが何かエラーをスローしたためにRESTコールが失敗した場合、トランザクションも保留中の同期アクションとして登録されることに注意してください。MAFは、次回MAFアプリケーションがRESTコールを行うときに実行を再試行します。このチェック・ボックスの選択を解除した場合は、MAFアプリケーションがオフラインか、またはRESTコールが失敗したときに、エラー・メッセージがエンド・ユーザーに表示されます。

  • Webサービス・エラーの表示: 選択した場合、RESTコールが失敗すると、エラー・メッセージのポップアップがユーザー・インタフェースに表示されます。これは、エラーを参照できるため、開発時に有用な設定です。本番にMAFアプリケーションを公開するときは、このチェック・ボックスの選択を解除することをお薦めします。通常は、RESTコールの失敗に関する技術的詳細をエンド・ユーザーに表示しないようにします。

  • リモート永続性マネージャ: 独自のリモート永続性マネージャを登録します。これは、MAFリモート永続性マネージャのデフォルトの動作を拡張する場合に便利です。

  • 「ローカル永続性マネージャ」: 独自のローカル永続性マネージャを登録します。これは、MAFローカル永続性マネージャのデフォルトの動作を拡張する場合に便利です。

6.10 クライアント・データ・モデルの生成

MAFがクライアント・データ・モデル用に生成するデータ・オブジェクトのプロジェクト名およびパッケージ名を指定します。

このタスクは、MAFアプリケーションにクライアント・データ・モデルを生成する一連のタスクのうちの1つです。詳細は、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」を参照してください。

図6-17は、クライアント・データ・モデル内のオブジェクトの場所およびパッケージ名を決定する「ジェネレータ設定」ページを示しています。

このページのフィールドは、次のように構成します。

  • プロジェクトへのクラスの追加: Javaクラスを生成するアプリケーション内のプロジェクトを選択します。MAFでは、デフォルトのApplicationControllerプロジェクトの使用をお薦めしています。これにより、アプリケーション・スコープのマネージドBeanおよびアプリケーション・ライフサイクル・メソッドのクラスを使用できます。また、これにより、複数のアプリケーション機能で同じデータ・オブジェクトを使用したときに、クラス・ローダーの問題が回避されます。各MAFアプリケーション機能はそれぞれ独自のクラス・ローダーを備えていますが、すべてがApplicationControllerプロジェクトの親クラス・ローダーを共有します。

  • データ・オブジェクト・パッケージ: データ・オブジェクトごとに生成されるJavaクラスで使用するJavaパッケージ名を指定します。

  • サービス・オブジェクト・パッケージ: サービス・オブジェクトごとに生成されるJavaクラスで使用するJavaパッケージ。データ・オブジェクトに少なくとも1つのRESTリソースが関連付けられている場合に、このようなクラスが生成されます。

  • データ・オブジェクト・クラスの上書き: 選択した場合、MAFは既存のデータ・オブジェクト・クラスを上書きします。以前の生成後にこれらのクラスにカスタム・コードを追加した場合は、このコードが失われます。

  • サービス・オブジェクト・クラスの上書き: 選択した場合、MAFは既存のサービス・オブジェクト・クラスを上書きします。以前の生成後にこれらのクラスにカスタム・コードを追加した場合は、このコードが失われます。ペイロード構造が変更されてもサービス・オブジェクト・クラスは通常変更する必要がないため、このチェック・ボックスはデフォルトでは選択が解除されています。また、このクラスには、生成後に追加したカスタム・コードが含まれる可能性が最も高くなります。

図6-17 クライアント・データ・モデルの生成

このイメージについては周囲のテキストで説明しています

6.11 MAFアプリケーションでのクライアント・データ・モデルの編集

MAFアプリケーションに以前に生成したクライアント・データ・モデルを変更できるウィザードの起動方法について説明します。

MAFは、MAFアプリケーションでのクライアント・データ・モデルの反復開発をサポートしています。クライアント・データ・モデルは、最初に作成した後で拡張および改良できます。次の2つのオプションのいずれかを使用します。

  • RESTサービスからのクライアント・データ・モデルウィザードを再実行して、新しいデータ・オブジェクトを検出するか、または既存のデータ・オブジェクトを編集します。このウィザードを再起動して、新しいデータ・オブジェクトを検出できます。既存のデータ・オブジェクトを変更しない場合は、関連する「選択」チェック・ボックスの選択を解除します。そうすると、最後のジェネレータ設定ウィザード・ページでの設定に関係なく、既存のデータ・オブジェクトが後続のウィザード・ページに表示されず、これらのデータ・オブジェクト用にJavaクラスが再生成されなくなります。

  • 図6-18に示した永続性マッピングの編集ウィザードを実行します。このウィザードは、クライアント・データ・モデルが含まれているプロジェクトを右クリックすると表示される永続性マッピングの編集コンテキスト・メニュー・エントリから起動します。

    「永続性マッピングの編集」ウィザードには、RESTサービスに接続するためのページや新しいデータ・オブジェクトを検出するためのページを除き、RESTサービスからのクライアント・データ・モデルウィザードと同じページが表示されます。このため、このウィザードは通常、既存のデータ・オブジェクトを編集するために使用します。ただし、RESTサービスに対するデータの読取りや書込みにRESTコールを必要としないデータ・オブジェクトを作成してSQLiteデータベースに格納する場合にも使用できます。

図6-18 クライアント・データ・モデルの編集

このイメージについては周囲のテキストで説明しています

6.12 MAFクライアント・データ・モデルDBPersistenceManagerの使用によるSQLiteデータベースへのアクセス

MAFクライアント・データ・モデルでは、MAFアプリケーション内でオンデバイスSQLiteデータベースにアクセスするためのAPI (oracle.maf.api.cdm.persistence.manager.DBPersistenceManager)が提供されます。

MAFクライアント・データ・モデルでは、SQLiteデータベースとのすべての相互作用がDBPersistenceManagerに委任されます。データベースへの接続方法で示されている下位レベルJDBC文を記述するかわりに、DBPersistenceManagerを使用します。クライアント・データ・モデルでのDBPersistenceManagerの役割の詳細は、MAFアプリケーションのクライアント・データ・モデルの概要を参照してください。DBPersistenceManager、およびそれが公開するメソッドの詳細は、Oracle Mobile Application Framework Java APIリファレンスを参照してください。

次の例では、DBPersistenceManagerのインスタンスを取得し、データ・オブジェクトに対するいくつかの検索操作およびその他の操作(挿入、更新および削除)を実行する方法を示します。次の例で示すコンストラクタの使用だけでなく、サービス・オブジェクトのインスタンスからgetLocalPersistenceManager()を呼び出すことでDBPersistenceManagerのインスタンスを取得することもできます。クライアント・データ・モデルのランタイム・オプションの設定で説明されている、クライアント・データ・モデル・ウィザードの「ランタイム・オプション」ページでカスタム・ローカル永続性マネージャを登録した場合は、これにより、DBPersistenceManagerのインスタンス、またはサブクラスが返されます。

/* Use the default constructor to get an instance of DBPersistenceManager.*/
DBPersistenceManager pm = new DBPersistenceManager();

/* findAll takes a class or class name as an argument and returns a list of all data objects.*/
List<Department> departments = pm.findAll(Department.class);


/* The overloaded find method returns a filtered list of data objects.
 *
 * There are various ways to specify your filter conditions, as demonstrated by the following examples.
 *
 * A quick search method that returns all employees where at least one of the String
 * attributes (firstName, lastName, emailAddress, and so on) starts with "king" (case insensitive).
 * This translates to use of the SQL LIKE operator where the search value is suffixed with %. */
List<Employee> emps = pm.find(Employee.class, "king");


/* A search method which allows you to specify the search attributes. It returns all employees where at least
 * one of the attributes passed in as list in the third argument starts with "king" (case insensitive). */
List<String> searchAttrs = new ArrayList<String>();
searchAttrs.add("firstName");
searchAttrs.add("lastName");
List<Employee> emps = pm.find(Employee.class, "king", searchAttrs);


/* This is a search method which allows you to specify separate values for each
 * attribute you want to search on, it will return all employees where the firstName
 * equals "Steven" and the lastName equals "King". The query is case sensitive.
 */
Map<String, String> searchAttrs = new HashMap<String, String>();
searchAttrs.put("firstName", "Steven");
searchAttrs.put("lastName", "King");
List<Employee> emps = pm.find(Employee.class, searchAttrs);


/* The findByKey method returns one data object based on its primary key.
 * It first checks the data object cache. If the department with id 10 does not exist in the cache, it queries
 * the database. If you do not want to check the cache, add a third boolean argument checkEntityCache, as demonstrated
 * by the second example
 */
Department dep = (Department) pm.findByKey(Department.class, new Object[] { 10 });
Department dep = (Department) pm.findByKey(Department.class, new Object[] { 10 }, false);


/* Insert, updates and remove a row for a data object instance.
 * MAF automatically commits the change if the second argument is true. If false, you
 * need to call pm.commit() later.
 * MAF generates the primary key attribute for you when calling insertEntity if you selected
 * the Generate Primary Key checkbox in the Runtime Options page of the MAF client data model wizard.
 */
pm.insertEntity(department, true);
pm.updateEntity(department, true);
pm.removeEntity(department, true);

カスタムSQL文の使用

前述のデータ・オブジェクトベースのAPIで、必要なSQL文を実行するためのオプションが提供されない場合は、カスタムSQL文を指定できます。SQL SELECT文とSQL DML文とは区別します。

SELECT文の結果をデータ・オブジェクトまたはデータ・オブジェクト・リストに変換する必要がある場合は、次の例で示すようにコードを使用します。

DBPersistenceManager pm = new DBPersistenceManager();
ClassMappingDescriptor descriptor = ClassMappingDescriptor.getInstance(Dealer.class);
StringBuffer sql = pm.getSqlSelectFromPart(descriptor);
sql.append(" WHERE SALES_ACCOUNT_ID not in (SELECT DEALER_ID FROM PRIORITY_ASSIGNMENT WHERE PRIORITY_ID=" +
	 priority.getId() + ")");
sql = pm.constructOrderByClause(sql, descriptor);
ResultSet set = pm.executeSqlSelect(sql.toString(), null);
List<Dealer> dealerList = pm.createEntitiesFromResultSet(set, descriptor.getAttributeMappingsDirect());

結果をデータ・オブジェクト・リストに変換する必要があるため、SELECT句にすべての列を含み、FROM句で、データ・オブジェクトに対応するテーブル名を使用する必要があります。getSqlSelectFromPartという便利なメソッドを使用することで、persistence-mapping.xmlファイルからデータ・オブジェクト・クラス・ディスクリプタを使用してSELECT句およびFROM句が自動的に作成されます。その後、SQL文にカスタムWHERE句を追加できます。カスタムORDER BY句を追加することもできますが、データ・オブジェクト・クラス・ディスクリプタで登録されたとおりのデフォルトorder byを使用する場合は、前述の例で示した便利なメソッドconstructOrderByClauseを使用できます。SQL SELECT文を作成したら、JDBC RowSetオブジェクトを返すexecuteSqlSelectメソッドを使用してそれを実行できます。次に、createEntitiesFromResultSetメソッドを使用してJDBC RowSetをデータ・オブジェクト・リストに変換します。

データ・オブジェクト・リストに変換できないすべてのSQL SELECT結果については、SQL文全体の定義、またJDBC RowSetの処理が可能です。次に、集約問合せの例を示します。

DBPersistenceManager pm = new DBPersistenceManager();
String sql = "SELECT AVG(SALARY) FROM EMPLOYEE";
ResultSet set = pm.executeSqlSelect(sql, null);
try {
  set.first();
  int averageSalary = set.getInt(1);
} 
catch (SQLException e) {
  sLog.severe("Error executing SQL statement: "+e.getLocalizedMessage());
}

単一行の挿入、更新または削除の場合は、通常は、前述のデータ・オブジェクトベースのAPIを使用します。ただし、一度に複数の行を挿入、更新または削除する必要がある場合は、executeSqlDmlメソッドを使用できます。次に、すべての事務員の給料を10%増加させる例を示します。

DBPersistenceManager pm = new DBPersistenceManager();
String sql = "UPDATE EMPLOYEE SET SALARY = SALARY * 1.1 WHERE JOB_ID='CLERK'";
pm.executeSqlDml(sql, null, true);

3番目のdoCommit引数がtrueの場合、バッチ更新が自動的にコミットされます。それがfalseに設定されている場合は、後でpm.commit()を呼び出す必要があります。

6.13 カスタム・リソースの定義

MAFクライアント・データ・モデルでサポートされている標準のCRUDリソースに直接マップしないカスタムRESTリソースをMAFアプリケーションのクライアント・データ・モデルに追加する方法について説明します。

「リソースの詳細」ウィザード・ページでは、「CRUD RESTリソース詳細の指定」で説明しているように、カスタム・リソースを追加できます。これを行うと、MAFはカスタム・リソースと同じ名前の追加のメソッドを次のシグネチャでサービス・オブジェクトに生成します。

public void doSomething(Department department) {
  invokeCustomMethod(department, "doSomething");
}

このアプローチの利点は、実装が高速かつ容易であることです。MAFアプリケーションがオフラインの場合や、サーバー・エラーのためにRESTコールが失敗した場合には、カスタム・リソース・アクションは保留中のデータ同期アクションとして登録されます。MAFは、後でMAFアプリケーションがオンライン・モードに戻ったときにコールを行います。つまり、「MAFアプリケーションからのオフライン・トランザクションの同期」で説明しているように、オフライン・モードの標準のCRUDトランザクションと同じように処理されます。

このアプローチの短所は、問合せパラメータおよびパス・パラメータを提供する方法およびリクエスト・ペイロードを提供する方法が制限されることです(これはシリアライズされたデータ・オブジェクトのみが可能)。問合せパラメータおよびパス・パラメータの値は、「CRUD RESTリソース詳細の指定」で説明しているオプションを使用して宣言的に定義できます。問合せパラメータおよびパス・パラメータによるURIパスの構築方法に完全な柔軟性を持たせる必要がある場合は、プログラムによるアプローチを採用し、RESTコールをJavaでコーディングした方が効率的です。

RESTリソースを起動するには、リモート永続性マネージャ(RestJSONPersistenceManagerか、またはOracle Mobile Cloud Service (MCS)に接続する場合にはMCSPersistenceManager)でinvokeRestServiceメソッドを使用します。これらのクラスおよびメソッドの詳細は、Oracle Mobile Application Framework Java APIリファレンスを参照してください。

また、「WebサービスにアクセスするためのRESTサービス・アダプタの作成」で説明しているように、RESTServiceAdapterを使用することもできます。ただし、invokeRestServiceメソッドには、次の利点があります。

  • 1行のコードでRESTコールを行います。

  • 200-299の範囲のHTMLステータス・コードですべてのレスポンスを正常に処理します。RESTServiceAdapterのようにステータス・コード201-299で例外がスローされることはありません。

  • Webサービス・ロギングを有効にした場合は、RESTコール詳細を簡単に表示できます。

  • MCSに接続する場合は、Oracle-Mobile-Backend-Idおよび(匿名) Authorizationヘッダー・パラメータを指定する必要はありません。

invokeRestServiceメソッドのシグネチャは次のとおりです。

public String invokeRestService(String connectionName, String requestType, String requestUri, 
                                              String payload, Map<String, String> headerParamMap, int retryLimit, boolean secured)

注意:

最後の引数(secured)は使用されません。後方互換性のために含まれています。

通常、invokeRestServiceメソッドを起動するサービス・オブジェクトにメソッドを追加します。その後、AMXページにメソッドをドラッグ・アンド・ドロップして、ユーザー・インタフェースからRESTコールを行うことができます。次に、このようなRESTコールを行うサンプルのメソッドを示します。

public void invokeSomeRestResource(String pathParamValue,String queryParamValue) {

  if (isOnline()) {
      RestJSONPersistenceManager rpm = new RestJSONPersistenceManager();      
      String uri = "/someResourcePath/"+pathParamValue+"?someQueryParam="+queryParamValue;
      String result = rpm.invokeRestService("MyRESTConn", "GET", uri, null, null, 0, false);
    // do something with the result
  }    
}

バックグラウンドでRESTコールを実行する場合、コードは次のようになります。

public void invokeSomeRestResource(String pathParamValue,String queryParamValue) {
  TaskExecutor.getInstance().execute(true, () -> {
    if (isOnline())
    {
      RestJSONPersistenceManager rpm = new RestJSONPersistenceManager();      
      String uri = "/someResourcePath/"+pathParamValue+"?someQueryParam="+queryParamValue;
      String result = rpm.invokeRestService("MyRESTConn", "GET", uri, null, null, 0, false);
      // do something with the result
    }    
  });
}

標準の「すべてのリソースの検索」のようにレスポンスをエンティティのリストに変換してSQLiteデータベースに格納する必要がある場合は、リモート永続性マネージャでhandleReadResponseメソッドを使用して、これをすべて自動的に行います。次に、このメソッドのシグネチャを示します。

public <E extends Entity> List<E> handleReadResponse(String jsonResponse, Class entityClass, 
                                                     String collectionElementName, String rowElementName,          
                                                     List<BindParamInfo> parentBindParamInfos, boolean deleteAllRows)

collectionElementName引数およびrowElementName引数は、標準のGETリソース用に指定している「ペイロード・リスト要素名」および「ペイロード行要素名」にマップされます。レスポンス・ペイロードの構造に基づいてこれらの引数の値を設定する方法は、「CRUD RESTリソース詳細の指定」を参照してください。レスポンスがトップレベルのオブジェクトとして配列を返す場合は、collectionElementNameの値としてルートを指定する必要があります。

parentBindParamInfos引数はnullのままにすることができ、deleteAllRows引数は廃止されています(後方互換性を維持するために含まれています)。レスポンス・ペイロードを処理する前にすべてのローカル行を削除する場合は、そのためのコードを自分で追加する必要があります。

次のコード・サンプルでは、レスポンス・ペイロードを処理してエンティティ・リストを作成するように前述の例を拡張する方法を示しています。

public void invokeSomeRestResource(String pathParamValue,String queryParamValue) {
  if (isOnline()) {
      RestJSONPersistenceManager rpm = new RestJSONPersistenceManager();      
      String uri = "/someResourcePath/"+pathParamValue+"?someQueryParam="+queryParamValue;
      String result = rpm.invokeRestService("MyRESTConn", "GET", uri, null, null, 0, false);
      List<Employee> emps = rpm.handleReadResponse(result, Employee.class, "root", null, null, false);
      setEntityList(emps);
  }    
}

6.14 CRUD RESTコール後のカスタム・ロジックの実行

ローカルおよび/またはリモート永続性マネージャに対してCRUD操作を実行するためにMAFがサービスクラス内で生成するメソッドを説明します。MAFでは、「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードからこれらのメソッドを生成します。

たとえば、部門サービス・クラスにはfindAllDepartmentsaveDepartmentおよびremoveDepartmentなどのメソッドがあります。これらのメソッドでは、間接的に、対応するRESTコールが行われます(「REST WebサービスからのMAFクライアント・データ・モデル」ウィザードでこれらのコールを構成してある場合)。そのため、RESTレスポンスに基づいてカスタム・ロジックを実行する必要がある場合は、これらのメソッドの最後にロジックを追加する可能性があります。ただし、これらのRESTコールをバックグラウンドで実行した場合(「ランタイム・オプション」ページで「バックグラウンドでのリモート読取り」および/または「バックグラウンドでのリモート書込み」チェック・ボックスを選択した場合)、これはうまくいきません。このシナリオでは、カスタム・ロジックは、別個のバックグラウンド・スレッドでRESTコールがまだ進行中の間にすでに実行されています。

必ずRESTコールがバックグラウンドで完了した後にカスタム・ロジックが実行されるよう、別のアプローチを取る必要があります。読取りRESTコール(GET)の後にカスタム・ロジックを追加する必要がある場合は、サービス・クラス内の次のメソッドのいずれかをオーバーライドできます。

  • executeRemoteFindAll

  • executeRemoteFindAllInParent

  • executeGetCanonical

executeRemoteFindAllをオーバーライドする、次の例で示すように、superへのコールの後にカスタム・ロジックを追加します。

@Override
protected List<Department> executeRemoteFindAll()
{
  // call super to get the new list of departments from REST call
  List<Department> result =  super.executeRemoteFindAll();
  // do some custom logic here
  ...

  // return department list
  return result;
}

書込みRESTコール(POSTPUTPATCHDELETE)の後にカスタム・ロジックを実行する必要がある場合は、リモート永続性マネージャのサブクラスを作成し、次のメソッドのいずれかをオーバーライドします。

  • insertEntity

  • updateEntity

  • mergeEntity

  • removeEntity

「永続性マッピングの編集」ウィザードを使用することで、サブクラス化する必要があるリモート永続性マネージャ・クラスを見つけます。図6-19で示す「ランタイム・オプション」ページに移動し、正しいデータ・オブジェクトを選択し、「リモート永続性マネージャ」フィールドからクラス名をコピーします。このクラスからサブクラス化した新しいJavaクラスを作成し、前にリストしたメソッドのうち1つまたは複数をオーバーライドします。MAFアプリケーション・ランタイムでカスタム・リモート永続性マネージャが使用されるようにするには、図6-19で示す「リモート永続性マネージャ」フィールドにサブクラスの完全修飾クラス名を入力します。「ランタイム・オプション」ページにアクセスするための「永続性マッピングの編集」ダイアログの起動の詳細は、MAFアプリケーションでのクライアント・データ・モデルの編集を参照してください。

図6-19 リモート永続性マネージャ

このイメージについては周囲のテキストで説明しています。

MAFによってサポートされるオフライン・トランザクションが原因で、書込みメソッドのリモート永続性マネージャをサブクラス化する必要があります。オフライン・モードでは、RESTコールは実行されませんが、かわりに、保留中の同期アクションとして登録されます。再度オンラインになったときに、MAFアプリケーションで、サービス・クラスをバイパスし、リモート永続性マネージャ・サブクラスを使用して直接RESTコールが実行されます。

RESTコールからの未加工のレスポンスに基づいてカスタム・ロジックを実行する必要がある場合は、MAFで処理が実行される前に、リモート永続性マネージャ内の次のメソッドをオーバーライドします。

public String invokeRestService(String connectionName, String requestType, String requestUri, 
                                String payload, Map111String,String222 headerParamMap, int retryLimit, boolean secured)

このメソッドは、MAF内のすべてのRESTコールを処理し、RESTコールのレスポンスを返します。superを呼び出した後、getLastResponseStatus()およびgetLastResponseHeaders()を呼び出してレスポンスに関する情報をさらに取得することもできます。

6.15 サービス・オブジェクトへのプログラムによるアクセス

サービス・オブジェクトのインスタンスへのプログラムによるアクセスを実現する方法について説明します。

通常、「データ・コントロール」パネルからのドラッグ・アンド・ドロップを使用してMAFアプリケーションのユーザー・インタフェースを作成するには、サービス・オブジェクトのデータ・コントロールを作成します。マネージドBeanまたはライフサイクル・リスナー・メソッドからサービス・オブジェクトにアクセスする場合は、次のように、サービス・オブジェクトのインスタンスを作成します。

DepartmentService service = new DepartmentService(); 

DepartmentServiceは、oracle.maf.impl.cdm.persistence.service.EntityCRUDServiceから拡張したものです。

「クライアント・データ・モデルのランタイム・オプションの設定」で説明しているように「ランタイム・オプション」ページで「自動問合せ」を選択し、「CRUD RESTリソースの定義」で説明しているように「すべてのリソースの検索」の値を指定した場合には、これがRESTコールをトリガーします。作成したインスタンスに対してプログラムによりこの自動問合せを実行しないようにする場合は、autoQueryをブール引数として取る次のコンストラクタを使用します。

DepartmentService service = new DepartmentService(false); 

自動問合せを実行する場合は、次のようにコードを記述します。

DepartmentService service = new DepartmentService(); 
List<Department> deps = service.getDepartment();
// do something with the departments

「ランタイム・オプション」ページで「バックグラウンドでのリモート読取り」チェック・ボックスを選択してRESTコールをバックグラウンドで実行する場合には、これが確実に機能するとはかぎりません。その場合、RESTコールがバックグラウンド・スレッドで実行されるため、getDepartment()メソッド・コールはローカル・データベースに格納されている部門のみを返します(ある場合)。したがって、最も安全な方法は次のコンストラクタを使用することです。

public DepartmentService(boolean doRemoteReadInBackground, boolean doRemoteWriteInBackground)
{
  super(false);
  setDoRemoteReadInBackground(doRemoteReadInBackground);
  setDoRemoteWriteInBackground(doRemoteWriteInBackground);
}

このコンストラクタは、autoQuery引数をfalseに設定してsuperをコールし、コンストラクタ・コールの指定に従ってremoteReadInBackgroundプロパティおよびremoteWriteInBackgroundプロパティを設定します。つまり、このコンストラクタを使用すると、「ランタイム・オプション」ページで行った(その結果persistence-mapping.xmlファイルに格納されている)選択の内容を無視するインスタンスを取得できます。

DepartmentService service = new DepartmentService(false,false); 
// get latest department list from server by making synchronous REST call
service.findAllDepartmentRemote; 
// get a handle in the department list
List<Department> deps = service.getDepartment();
// do something with the department list

マネージドBeanコードでは、データ・コントロールで使用されるサービス・オブジェクト・インスタンスへのアクセスが必要になる場合があります。これを行うには、次の便利なメソッドを使用します。

DepartmentService service = (DepartmentService) EntityUtils.getEntityCRUDService(Department.class);

このメソッドは、サービス・オブジェクト・クラスの名前でデータ・コントロール・インスタンスを検索します。ただし、データ・コントロールをまだインスタンス化しないうちにこのメソッドを使用した場合(つまり、AMXページで使用した場合)、前に説明したように、デフォルトのコンストラクタを使用して新規インスタンスを作成するため、不要なRESTコールをトリガーする場合があることに注意してください。データ・コントロール・インスタンスは、アプリケーション機能のコンテキストに存在します。2つの異なるアプリケーション機能のAMXページで同じデータ・コントロールを使用した場合は、基礎となるサービス・オブジェクトのインスタンスが2つ存在することになります。getEntityCRUDServiceメソッドを実行するアプリケーション機能コンテキストによって、どのインスタンスが返されるかが決まります。

マネージドBeanコードでデータ・コントロール・インスタンスを操作する必要性を減らすため、可能なかぎり多くのロジックをサービス・クラスに移動します。多数の値バインディング式およびメソッド・バインディング式を評価し、その後でこれらの多数のメソッド・バインディングを実行する場合は、コーディング方針を見直すことをお薦めします。

最後に、カスタムJavaコードでローカルSQLiteデータベースにのみアクセスする必要があり、RESTコールを行う必要がない場合は、サービス・オブジェクト・インスタンスを作成する必要はありません。かわりに、oracle.maf.api.cdm.persistence.manager.DBPersistenceManagerのインスタンスを使用して、データ・オブジェクトの問合せまたは操作を行います。詳細は、Oracle Mobile Application Framework Java APIリファレンスを参照してください。

6.16 主キーの使用の理解

SQLiteデータベース内の行を一意に識別できるようにするには、すべてのデータ・オブジェクトに主キーが必要となります。また、MAFでは、データ・オブジェクト・キャッシュでのデータ・オブジェクト作成を最小限に抑えるため、およびデータ・オブジェクトの複数のインスタンスが作成されないようにするために、主キーが使用されます。

キャッシュから特定のデータ・オブジェクト・インスタンスを取得するには、次のメソッドを使用します。

EntityCache.getInstance().findByUID(Class entityClass, Object[] key)

キャッシュから、またはデータ・オブジェクトがキャッシュされていない場合にデータベースからデータ・オブジェクトを取得するには、DBPersistenceManagerクラスから次のメソッドを使用します。

findByKey(Class entityClass, Object[] key)

主キーは、複数の属性/列で構成される複合キーにできます。これは、前述のメソッドのkey引数がオブジェクト配列を取るためです。主キーが単一の数値属性である場合は、クライアント・データ・モデルのランタイム・オプションの設定で説明されている「ランタイム・オプション」ページ内の「主キーの生成」チェック・ボックスを選択してあると、MAFで自動的に主キーが生成されます。フレームワークまたはカスタム・コードによってDBPersistenceManagerinsertEntityメソッドが呼び出されると、MAFにより、SQLiteデータベースに現在の最大値が照会され、この値が1増分されます。

次のメソッドを使用することで、自分で主キーを生成することもできます。

EntityUtils.generatePrimaryKey(Entity entity, int increment)

注意:

後者のメソッドは、データ・オブジェクトに対して「主キーの生成」チェック・ボックスを選択した場合のみ機能します。これは、それによってpersistence-mapping.xmlファイル内のこのフラグがチェックされるためです。

サーバーで生成された主キー値のMAFによる管理の理解

新しいデータ・オブジェクト・インスタンスのために作成または生成した主キー値は、一時主キーとみなされます。もちろん、この主キーがサーバー側で一意であることは保証されません。通常は、データ・オブジェクトをリモート・サーバーに挿入するRESTサービスを起動すると(ウィザードで指定した「リソースの作成」)、リモート・サーバーによって一意の主キーが生成されます。

データ・オブジェクトを挿入するRESTコールで、レスポンスで、サーバーによって生成された新しい値があるデータ・オブジェクトが返された場合、MAFクライアント・データ・モデルにより、サーバーで生成された主キーで一時主キーが自動的に更新されます。MAFクライアント・データ・モデルにより、一時主キーを含むデータベース行が削除され、サーバーで生成されたキーを含む新しい行が挿入されます。また、データベース・オブジェクト・キャッシュが更新されます。

このMAFクライアント・データ・モデル機能を役立てるには、「リソースの作成」エンドポイントにおいてレスポンスでデータ・オブジェクト全体が返されることを確認してください。

SQLite自動増分機能

MAFでは、データ・オブジェクト・キャッシュ内のインスタンスを識別するため、およびMAFアプリケーションでサーバーから最新データがフェッチされるときにSQLiteデータベース内の既存行を更新するために主キーが使用されるため、SQLiteの自動増分機能を使用しないようにしてください。この理由から、SQLiteの自動増分機能ではなく、リモート・サーバーからのペイロードに含まれる1つまたは複数のデータ・オブジェクト属性を使用して主キーを指定することをお薦めします。

サーバーから取得されるデータ・オブジェクト・インスタンスがないデータ・オブジェクトのためにSQLiteの自動増分機能を使用するのはかまいません。つまり、ここでは、SQLiteデータベースにデータを読み込むために呼び出されるGETリソースはありません。

SQLiteの自動増分機能の詳細は、SQLiteのドキュメントを参照してください。

6.17 フィルタされたエンティティ・リストの使用

MAFアプリケーションのUIでのフィルタされたリストの作成を容易にするためにMAFクライアント・データ・モデルが生成するメソッドを説明します。

MAFでは、データ・オブジェクト・インスタンスのコレクションを返す、データ・オブジェクトのCRUDサービス・クラス内のゲッター・メソッドが生成されます。たとえば、従業員データ・オブジェクトのサービス・クラス(EmployeeService)には次のメソッドがあります。

public List<Employee> getEmployee() {   
  return getEntityList(); 
}  

EntityCRUDServiceスーパークラスでは、返されたリストはプライベート・メンバー変数(private EntityList<E> entityList)に格納されます。このリストには、ローカルSQLiteデータベースから、および/またはクライアント・データ・モデルのランタイム・オプションの設定で説明されているように「ランタイム・オプション」ページ内の「自動問合せ」チェック・ボックスを選択した場合にはFind All RESTリソースへのコールから取得されたすべてのデータ・オブジェクト・インスタンスが含まれています。

ユーザー・インタフェース内のクイック検索フィールドに基づいてこのリストをフィルタするには、データ・オブジェクトCRUDサービス・クラスで生成される、find[entityName]メソッドを使用します。たとえば、次のメソッドは、従業員データ・オブジェクトのために生成されます。

public void findEmployee(String searchValue) {
  super.find(searchValue);
}

検索フィールドおよびコマンド・ボタンをレンダリングしてfind[entityName]メソッドを呼び出すには、メソッドを「データ・コントロール」パネルから自分のAMXページにドラッグ・アンド・ドロップします。エンド・ユーザーがそのコマンド・ボタンをタップしてfind[entityName]メソッドを呼び出すと、find[entityName]メソッドはDBPersistenceManagerクラス内のfindメソッドに委任します。DBPersistenceManagerクラスの詳細は、MAFクライアント・データ・モデルDBPersistenceManagerの使用によるSQLiteデータベースへのアクセスおよびOracle Mobile Application Framework Java APIリファレンスを参照してください。findメソッドから返される結果は、entityList変数の新しいコンテンツとして格納されます。エンド・ユーザーがコマンド・ボタンをクリックした後、リストを正しくリフレッシュするために、データ変更イベントがユーザー・インタフェースに送信されます。

エンティティ・リストをフィルタするカスタム・メソッドを記述することもできます。次の例では、従業員のリストを事務員のみにフィルタします。

public void filterClerks()
{
  DBPersistenceManager pm = new DBPersistenceManager();
  Map<String,String> searchAttrs = new HashMap<String,String>();
  searchAttrs.put("jobId","CLERK");
  List<Employee> clerks = pm.find(Employee.class,searchAttrs); 
  setEntityList(clerks);
}

setEntityListを呼び出すとentityList変数が更新され、setEntityListが呼び出されると、必要なデータ変更イベントがユーザー・インタフェースに送信されます。

注意:

このメソッドがUIアクションを介して呼び出されるか、バックグラウンド・スレッドでJavaコードを介して呼び出されるかは問題ではありません。

たとえば、アプリケーションのユーザー・インタフェースで、フィルタされたリストを一度に複数表示する必要があるとします。たとえば、従業員のリストと事務員のリストを表示する必要があるとします。このシナリオでは、entityListによってすでにすべての従業員がユーザー・インタフェースに表示されているため、filterClerksメソッドではentityListメンバー変数は更新できません。解決策は、事務員のリストを返すゲッター・メソッドの追加です。これにより、事務員のリストを表示するAMXページ上にドラッグ・アンド・ドロップできる、事務員コレクション属性がEmployeeServiceデータ・コントロールに追加されます。次のコード例では、そのようなゲッター・メソッドを示します。

public List<Employee> getClerks()
{
  DBPersistenceManager pm = new DBPersistenceManager();
  Map<String,String> searchAttrs = new HashMap<String,String>();
  searchAttrs.put("jobId","CLERK");
  List<Employee> clerks = pm.find(Employee.class,searchAttrs); 
  return clerks;
}

@Override
protected void setEntityList(List<Employee> entityList)
{
  super.setEntityList(entityList);
  // we also need to refresh the clerks list
  getPropertyChangeSupport().firePropertyChange("clerks", null, getClerks());
  getProviderChangeSupport().fireProviderRefresh("clerks");      
}

前の例では、Find All RESTリソースを呼び出すことでバックグラウンドで最新の従業員リストを取得するという状況に対処するよう、setEntityListメソッドをオーバーライドしています。MAFアプリケーションでバックグラウンドでFind All RESTコールを実行した場合、レスポンスが返されるとsetEntityListが呼び出され、データベースが、レスポンス・ペイロードに含まれる最新のデータ・オブジェクト・インスタンス・セットで更新されます。この例では、ユーザー・インタフェースに、すべての従業員のリストと事務員のリストが示されます。RESTコールが完了したときに、両方のリストが更新されるようにする必要があります。setEntityListメソッドのオーバーライドによって、RESTサービスから最新の従業員セットが取得されるとgetClerksメソッドが再度実行され、事務員リストをリフレッシュするためにデータ変更イベントが送信されるようになります。

6.18 MAFクライアント・データ・モデルに基づくユーザー・インタフェースの作成

クライアント・データ・モデルを生成したMAFアプリケーションでは、開発作業の簡素化のためにMAFから提供される数多くの機能を利用できます。

クライアント・データ・モデルの作成後、通常、クライアント・データ・モデルが生成したエンティティ・サービス・クラスごとにデータ・コントロールを作成します。これらのデータ・コントロールには、JDeveloperの「データ・コントロール」パレットから操作およびコレクションをドラッグ・アンド・ドロップしてMAF AMXページを構築できるようにするメソッドが多数含まれています。詳細は、「クライアント・データ・モデルからデータ・コントロールを作成する方法」を参照してください。

「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」で説明しているようにクライアント・データ・モデルを作成した場合は、MAFアプリケーションのユーザー・インタフェース・レイヤーを構築およびテストする際の生産性を高めるためにMAFに用意されている次の機能を利用できます。

  • 「MAFユーザー・インタフェース・ジェネレータ」ウィザードを使用して、クライアント・データ・モデルをテストし、MAFアプリケーションのユーザー・インタフェースのプロトタイプを作成します。このウィザードは、タスク・フロー、AMXページ、データ・バインディングなどを備えた完全なMAFアプリケーション機能を生成します。このウィザードを使用するには、データ・コントロールを作成し、そのデータ・コントロールからアプリケーション機能を生成します。詳細は、「MAFユーザー・インタフェース・ジェネレータを使用する方法」を参照してください。

  • MAFに付属している再利用可能なデータ同期アプリケーション機能を使用して、保留中のデータ同期アクションを表示します。あるいは、データ同期サービス・データ・コントロールを使用して独自のAMXページを作成します。

  • MAFアプリケーションが実際にはインターネットに接続されている間もオフラインであるかのように動作するようにします。

  • ビジュアル・インジケータを追加して、MAFアプリケーションがバックグラウンドで作業を実行中であることをエンド・ユーザーに示します。このビジュアル・インジケータは通常、MAFアプリケーションがリモート・サーバーに対してデータの読取りまたは書込みを実行中であることをエンド・ユーザーに通知するために使用します。

  • MAFに付属しているWebサービス・コールというアプリケーション機能を使用して、MAFアプリケーションが行うRESTコールを調べます。

6.18.1 クライアント・データ・モデルからデータ・コントロールを作成する方法

MAFアプリケーションのクライアント・データ・モデルの生成時に作成されるサービス・オブジェクトからデータ・コントロールを作成する方法について説明します。

「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」で説明しているようにクライアント・データ・モデルの作成が完了したら、通常、後者のタスク中に生成されたサービス・オブジェクトからデータ・コントロールを作成します。これらのデータ・コントロールにより、アプリケーションのユーザー・インタフェースの作成が容易になります。JDeveloperの「データ・コントロール」パネルからコレクション、属性または操作をドラッグしてAMXページにドロップできます。このとき、MAFにより、AMXページにデータまたはUIコントロールをレンダリングするのに適したAMXコンポーネントを選択するように求められます。あるいは、「MAFユーザー・インタフェース・ジェネレータを使用する方法」で説明しているように、「MAFユーザー・インタフェース・ジェネレータ」ウィザードを使用してデータ・コントロールからアプリケーション機能を生成できます。

クライアント・データ・モデルからデータ・コントロールを作成するには:

  1. 「アプリケーション」ウィンドウで、クライアント・データ・モデル・ウィザードが生成したサービス・オブジェクトに移動します。

    サービス・オブジェクトの場所は、クライアント・データ・モデル・ウィザードで選択したオプションによって異なります。たとえば、図6-20は、MAFアプリケーションのApplicationControllerプロジェクトのDepartmentServiceサービス・オブジェクトおよびEmployeeServiceサービス・オブジェクトを示しています。

    図6-20 クライアント・データ・モデルのサービス・オブジェクト

    このイメージについては周囲のテキストで説明しています
  2. 「アプリケーション」ウィンドウで、サービス・オブジェクト(たとえば、DepartmentService.java)を右クリックし、表示されたコンテキスト・メニューから「データ・コントロールの作成」を選択します。

  3. 表示された「Beanデータ・コントロールの作成」ウィザードのフィールドに入力し、「終了」をクリックします。

6.18.2 クライアント・データ・モデルからデータ・コントロールを作成する場合の処理

MAFは、AMXページにドラッグ・アンド・ドロップできる様々な要素および操作を使用して、サービス・オブジェクトからデータ・コントロールを生成します。

このデータ・コントロールは、「MAFユーザー・インタフェース・ジェネレータを使用する方法」で説明しているように、「MAFユーザー・インタフェース・ジェネレータ」ウィザードでアプリケーション機能を作成する場合にも使用できます。

図6-21 クライアント・データ・モデルのサービス・オブジェクトから作成されたデータ・コントロール

前後のテキストでこのイメージを説明しています

6.18.3 MAFユーザー・インタフェース・ジェネレータを使用する方法

MAFアプリケーションにクライアント・データ・モデルを生成した場合は、「MAFユーザー・インタフェース・ジェネレータ」ウィザードを使用して、タスク・フロー、AMXページおよびデータ・バインディングを備えたMAFアプリケーション機能を作成します。

このウィザードでは、クライアント・データ・モデルをテストし、MAFアプリケーションのプロトタイプのユーザー・インタフェースを作成できます。ウィザードを使用する前に、「MAFアプリケーションでのクライアント・データ・モデルの作成の概要」で説明しているように、クライアント・データ・モデルを作成します。クライアント・データ・モデルを作成すると作成されるサービス・オブジェクトからデータ・コントロールを生成します。MAFアプリケーション機能を生成するデータ・コントロールがJDeveloperの「データ・コントロール」ウィンドウに表示されることを確認してください。「リフレッシュ」アイコンをクリックすることが必要になる場合があります。

ウィザードは、データ・コントロールが公開するデータ・オブジェクトごとにリスト・ビュー・ページおよびフォーム・ページを生成します。リスト・ビュー・ページに公開するデータ・オブジェクト属性を選択できます。フォーム・ページには、すべてのデータ・オブジェクト属性が表示されます。

「MAFユーザー・インタフェース・ジェネレータ」ウィザードを使用するには:

  1. メイン・メニューで、「ファイル」を選択し、「ギャラリから」を選択します。

  2. 「新規ギャラリ」の「クライアント層」カテゴリの「モバイル・アプリケーション・フレームワーク」ノードで、「MAFユーザー・インタフェース・ジェネレータ」をダブルクリックします。

  3. ようこそページの「次へ」をクリックし、「データ・コントロールの選択」ページで、MAFアプリケーション機能を生成するデータ・コントロールを選択します。

  4. 「MAFアプリケーションの保護」で説明しているようにMAFアプリケーションのセキュリティをすでに構成している場合は、「データ・コントロールの選択」ページの「機能セキュリティの有効化」チェック・ボックスを選択できます。このタスクは後で実行できます。

  5. 「次へ」をクリックして、図6-22に示す「データ・オブジェクトUI設定」ページに移動し、次のように値を構成します。

    • データ・オブジェクト: ドロップダウン・リストからデータ・オブジェクトを選択し、このオブジェクトの表示タイトルと、エンド・ユーザーが実行できるようにユーザー・インタフェースに公開する操作(オブジェクトの作成や更新や削除など)を構成します。「CRUD RESTリソースの定義」で説明しているようにCRUD RESTリソースを定義した場合は、「作成可能」「更新可能」および「削除可能」のチェック・ボックスを選択します。

    • 親ページに表示: 親データ・オブジェクトのフォーム・ページ内に子データ・オブジェクトのリスト・ビューを含める子データ・オブジェクトを選択します。別個のページに表示するチェック・ボックスの選択を解除します。このチェック・ボックスを使用する場合は、「データ・オブジェクトの親子関係の指定」で説明しているように、親子関係を構成しておくことが前提となります。

    • リスト属性: リスト・ビュー・ページに表示するデータ・オブジェクト属性を指定します。リスト区切りを選択することもできます。

    図6-22 MAFユーザー・インタフェース・ジェネレータによって生成されたページのユーザー・インタフェースの構成

    このイメージについては周囲のテキストで説明しています
  6. 「終了」をクリックして、ユーザー・インタフェースを含むMAFアプリケーション機能を生成します。

6.18.4 ユーザー・インタフェースを生成する場合の処理

「MAFユーザー・インタフェース・ジェネレータ」ウィザードを完了すると、MAFはMAFアプリケーションに次の変更を加えます。

  • maf-feature.xmlファイルに新規に作成したMAFアプリケーション機能を追加します。

  • Web Contentディレクトリのサブディレクトリにタスク・フローを生成します。サブディレクトリの名前は、データ・オブジェクト(たとえば、Department)の名前から導出されます。

  • 生成したタスク・フローにビュー・アクティビティごとにAMXページを生成し、生成したAMXページのAMXページ定義を生成します。

  • adfc-mobile-config.xmlファイルにGoToFeatureおよびConnectivityマネージドBeanを追加します。生成したAMXページがこれらのマネージドBeanを使用します。

  • 新規に作成したMAFアプリケーション機能への参照に加え、クライアント・データ・モデルを生成するとMAFに含まれるその他の2つのアプリケーション機能への参照も追加します。これらは、データ同期アプリケーション機能とWebサービス・コール・アプリケーション機能です。これらのアプリケーション機能の使用の詳細は、「MAFアプリケーションからのオフライン・トランザクションの同期」および「MAFアプリケーションでのWebサービス・コールの検査」を参照してください。

6.19 MAFアプリケーションからのオフライン・トランザクションの同期

MAFアプリケーションでは、アプリケーションがオフライン・モードのときに、エンド・ユーザーがトランザクションを実行できるようにすることができます。MAFは、アプリケーションが次にオンライン・モードになったときに、トランザクションごとにデータ同期アクションを実行します。

このコンテキストでのトランザクションは、RESTコールによるデータの作成、変更または削除を伴う、サービス・オブジェクトに対するメソッドの起動です。saveDepartment(Department)などサービス・オブジェクトのメソッドを起動すると、MAFはコール可能な対応するRESTリソースがあるかどうかをチェックします。対応するRESTリソースがない場合、MAFはオンデバイスSQLiteデータベースに対して適宜メソッドを起動します。コール可能な対応するRESTリソースがある場合、MAFはデータ同期アクションを作成します。データ同期アクションは、実行するリソースのタイプ(挿入、更新、削除またはカスタム・アクション)およびトランザクションが必要とするデータ・オブジェクト・インスタンスのすべてのデータを保持します。

MAFアプリケーションがオンライン・モードになると、MAFは同期アクションを起動し、対応するRESTリソースを起動します。MAFアプリケーションがオフライン・モードで、データ・オブジェクトに対するオフライン・トランザクションを有効にした場合、MAFはデータ同期アクションを登録し、それを保留中の同期アクションとして格納します。MAFは、MAFアプリケーションが次にオンライン・モードになったときに、アクションを同期します。MAFは、同期するときにトランザクションがコミットされる正確な順序を保持します。

データ・オブジェクトのオフライン・トランザクションを有効にするには、「クライアント・データ・モデルのランタイム・オプションの設定」で説明しているように、オフライン・トランザクションの有効化チェック・ボックスを選択します。データ・オブジェクトに対するオフライン・トランザクションを無効にした場合、エンド・ユーザーがデータ・オブジェクトに対してオフライン・トランザクションを実行しようとすると、MAFは「デバイスはオフラインです。」という例外をスローします。この例外を防ぐには、MAFアプリケーションがオフライン・モードのときにはUIコントロールを無効にして、エンド・ユーザーが例外をスローするトランザクションを作成できないようにします。

MAFは、SQLiteデータベースのPENDING_SYNCH_ACTIONS表にデータ同期アクションを格納します。データ・オブジェクトのSQLiteデータベース表には、データ同期アクションに関連する情報は格納されません。たとえば、MAFアプリケーションがオフライン・モードのときに、エンド・ユーザーが部門を削除したとします。このアクションは、SQLiteデータベースのDEPARTMENTS表から対応する行を削除し、対応するデータ同期アクションをPENDING_SYNCH_ACTIONS表に追加します。MAFアプリケーションが次にオンライン・モードになったときに、部門の削除というデータ同期アクションに関連付けられたRESTアクションが実行されます。これにより、関連付けられたRESTコールが実行されたかどうかに関係なく、エンド・ユーザーによって実行された最新のトランザクションがローカルSQLiteデータベース表に反映されるようになります。

MAFアプリケーションがオフライン・モードからオンライン・モードに戻った場合、MAFはアプリケーションがRESTコールを起動するのを待機します。このイベントが発生すると、MAFはRESTコールを処理する前に保留中のデータ同期アクションを同期します。この同期により、MAFアプリケーションに対する後続のRESTコールおよびレスポンスでは廃止されたデータが使用されなくなります。自動同期をトリガーするRESTコールがない場合でも、MAFアプリケーションの任意のサービス・オブジェクトからsynchronize(boolean)メソッドを起動することで、MAFアプリケーションがオンライン・モードに戻ったときに、この自動同期を明示的に起動できます。synchronize(boolean)メソッドは、すべてのサービス・オブジェクト・クラスの拡張元となるoracle.maf.impl.cdm.persistence.service.EntityCRUDServiceクラスに用意されています。このメソッドを任意のサービス・オブジェクト・クラスから一度起動すると、MAFアプリケーションで保留中のすべてのデータ同期アクションに対して自動同期が実行されます。synchronizeのブール引数によって、同期がバックグラウンドで行われるか(true)、フォアグラウンドで行われるか(false)が決まります。お薦めしませんが、MAFアプリケーションのデフォルトの動作を無効にして、RESTコールを起動する前に保留中の同期アクションを同期することもできます。詳細は、「自動同期の無効化に関する必知事項」を参照してください。

MAFアプリケーションでは、オンライン・モードに戻ってデータを同期したときに、データ同期の競合が発生するかどうかを検出することはできません。たとえば、MAFアプリケーションがオフライン・モードのときに、MAFアプリケーションのエンド・ユーザーが部門を更新したとします。別の場所で、同じデータ・セットにアクセスするWebアプリケーションの別のユーザーが同じ部門情報を変更します。MAFでは、この後者の変更を検出できません。MAFアプリケーションがオンラインに戻ったときに、MAFはPENDING_SYNCH_ACTIONS表での変更を同期しようとします。今説明した問題を解決し、回避するには、MAFアプリケーションがアクセスするデータ・セットにすべてのアプリケーション(モバイルやWebなど)がアクセスする場所でデータ同期の競合を特定して解決する必要があります。

MAFが対応するRESTリソースをコールして保留中の同期アクションを同期しようとしたときに、サーバーが停止しているなどの理由で、RESTコールがアクションに対してエラー・レスポンスを返すことがあります。そうなった場合、MAFはPENDING_SYNCH_ACTIONS表にデータ同期アクションを保持します。また、同期試行および同期エラーのタイムスタンプでアクションを更新します。1つ以上のアクションが失敗しても、MAFは表にある残りのデータ同期アクションの処理を続行します。MAFは、次回同期を実行するときに、これらの保留中のデータ同期アクションを再試行します。これらの保留中の同期アクションをエンド・ユーザーに公開して、まだ同期されていないアクションを表示してどのように対処するかを決定できるようにすることができます。詳細は、「保留中の同期アクションを表示する方法」を参照してください。また、同期アクションの完了時にMAFアプリケーションで実行するカスタム・ロジックを記述することもできます。たとえば、同期の失敗に応じて実行するコードを記述できます。詳細は、「失敗した同期アクションを処理するためのカスタム・ロジックを追加する方法」を参照してください。

6.19.1 保留中の同期アクションを表示する方法

エンド・ユーザーが保留中の同期アクションを表示および削除できるアプリケーション機能を表示するには、MAFアプリケーションにDataSyncFeature.jar機能アーカイブを追加します。

追加すると、保留中の同期アクションを表示するためのメニューを備えたアプリケーション機能がMAFアプリケーションに組み込まれます。エンド・ユーザーは、各保留中の同期アクションをタップして、詳細を表示し、アクションを削除するか、またはMAFが同期を再試行するまでそのままにしておくかを決定できます。図6-23は、この機能アーカイブが追加されたMAFアプリケーションのメニュー・エントリと保留中の同期アクション画面の合成イメージを示しています。

図6-23 保留中の同期アクションの表示

テキストについては周囲のテキストで説明しています。

注意:

「MAFユーザー・インタフェース・ジェネレータ」ウィザードは、完了時にこのFARをMAFアプリケーションに自動的に追加します。詳細は、「MAFクライアント・データ・モデルに基づくユーザー・インタフェースの作成」を参照してください。

DataSyncFeature.jar FARを追加するには:

  1. メイン・メニューで、「アプリケーション」および「アプリケーション・プロパティ」を選択します。

  2. 「アプリケーション・プロパティ」ダイアログで、「ライブラリとクラスパス」ページに移動し、「JAR/ディレクトリの追加」をクリックします。

  3. 表示された「アーカイブまたはディレクトリの追加」ダイアログで、JDeveloperインストールのjdeveloper/jdev/extensions/oracle.maf/FARs/CDMディレクトリに移動し、MAFアプリケーションのクラスパス・エントリの下に表示されるようにDataSynchFeature.jarファイルを選択します。

  4. 「OK」をクリックしてダイアログを閉じます。

  5. maf-application.xmlファイルの概要エディタの「機能参照」ページで、図6-24に示すように、機能参照の挿入ダイアログからデータ同期機能を選択してアプリケーションに追加します。

    図6-24 保留中の同期アクションを表示するためのFARの追加

    このイメージについては周囲のテキストで説明しています。

6.19.2 失敗した同期アクションを処理するためのカスタム・ロジックを追加する方法

失敗した同期アクションをプログラムにより処理する場合は、データ同期が完了したらMAFアプリケーションで実行するカスタム・コードを記述します。

MAFアプリケーションでJavaコードを記述して登録するには、次の手順を実行します。

  1. oracle.maf.impl.cdm.persistence.service.DataSynchManagerから拡張するJavaクラスを作成します。

  2. データ同期アクションの完了後にカスタム・ロジックを追加するように、dataSynchFinishedメソッドをオーバーライドします。

    protected void dataSynchFinished(java.util.List<DataSynchAction> succeededDataSynchActions, 
                                             java.util.List<DataSynchAction> failedDataSynchActions)

    dataSynchFinishedメソッドには、引数が2つあります。正常に完了した同期アクションのリストと、失敗した同期アクションのリストです。このメソッドを使用すると、たとえば、1つ以上のトランザクションが失敗し、後で再試行が必要であることをエンド・ユーザーに警告したり、すべての保留中のデータ同期アクションが正常に処理されたことを通知できます。

    同期ポリシーを導入するためのJavaコードをこのメソッドに追加します。次の簡単な例では、正常に完了した同期アクションと失敗した同期アクションの数をユーザーに通知しています。

    package application.model.service;
    
    import java.util.List;    
    import oracle.adfmf.framework.exception.AdfException;
    import oracle.maf.impl.cdm.util.MessageUtils;
    import oracle.maf.api.cdm.persistence.service.DataSynchAction;
    import oracle.maf.impl.cdm.persistence.service.DataSynchManager;
    
    public class MyDataSynchManager extends DataSynchManager {
    
      public DataSynchManager() {
        super();
      }
    
      @Override
      protected void dataSynchFinished(List<DataSynchAction> succeededDataSynchActions,
                                       List<DataSynchAction> failedDataSynchActions)  {
        int ok = succeededDataSynchActions.size();
        int fails = failedDataSynchActions.size();
        int total = ok + fails;
        MessageUtils.handleMessage(AdfException.INFO,
           total + " data synch actions completed. Successful: " + ok + ", Failed: " + fails);
      }
    }
    
    
  3. 次の例に示すように、アプリケーションのmobile-persistence-config.propertiesファイルにクラスを登録します。

    datasync.manager.class=application.model.service.MyDataSynchManager

    mobile-persistence-config.propertiesファイルは、ApplicationRootDirectory/ApplicationController/src/META-INF/フォルダにあります。

6.19.3 自動同期の無効化に関する必知事項

MAFアプリケーションからのトランザクションの自動同期を無効にできます。

MAFアプリケーションからのトランザクションの自動同期を無効にするには:

  1. oracle.maf.impl.cdm.persistence.service.EntityCRUDServiceを拡張する新しい抽象Javaクラスを作成します。

  2. synchronizeメソッドが何も実行しないように、このメソッドをオーバーライドし、super.synchronizeへのコールをコメント・アウトします。

  3. EntityCRUDServiceから拡張するのではなく、先ほど作成したサブクラスから拡張するように、サービス・オブジェクト・クラスを変更します。

自動同期を無効にする場合は、エンド・ユーザーが同期アクションを明示的に起動できるようにMAFアプリケーションを構成します。データ同期を明示的にトリガーするには、次の文を使用します。

new DataSynchService().synchronize(true); 

ブール引数によって、同期がバックグラウンドで行われるか(true)、フォアグラウンドで行われるか(false)が決まります。DataSynchServiceクラスは、oracle.maf.api.cdm.persistence.serviceパッケージにあります。詳細は、Oracle Mobile Application Framework Java APIリファレンスを参照してください。

トランザクションの自動同期を無効にすると、古くなったデータがアプリケーションに存在し、ユーザー操作性が混乱する可能性があるため、無効にしないことをお薦めします。次の例のユーザー(John)のユースケースは、この点を示しています。Johnは、自分のアプリケーションで次のアクションを実行します。

  • アプリケーションをオンライン・モードで起動するときに、部門の最新のリストを取得します。

  • オフライン・モードで部門10の名前を変更します。

  • オフライン・モードで部門20を削除します。

  • オフライン・モードで新規部門280を作成します。

  • アプリケーションを終了します。

  • Johnは、再度アプリケーションをオンライン・モードで起動し、部門の最新のリストをサーバーから取得しますが、3個の保留中の同期アクションがまだ処理されていません。

  • Johnには現在、部門10の古い部門名が表示されています。

  • Johnは部門20をすでに削除しましたが、現在再び表示されています。

  • MAFアプリケーション開発者がデータ・オブジェクトの「すべてのリソースの検索」に対する「ローカル行の削除」チェック・ボックスを選択した場合には、Johnが作成した新規部門(280)は二度と表示されません。

Johnが同期アクションを手動で起動した場合にのみ、(ユーザー・インタフェース・コントロールまたはアプリケーションの再起動によって)サーバーから部門リストを最新のデータで再びリフレッシュすると、オフライン・モードで加えた変更を含む最新のデータが再び表示されます。

6.20 クライアント・データ・モデルによるデータ変更イベントのサポートの理解

基礎となるデータ・コレクションでのデータ変更イベントに応えてMAFアプリケーションのユーザー・インタフェースをリフレッシュするためにMAFクライアント・データ・モデルで使用されるAPIを説明します。

MAFクライアント・データ・モデルによって生成されるデータおよびサービス・クラスは、MAFでサポートされている両方のタイプの変更イベント(プロパティおよびプロバイダ)ですぐに利用できます。これは、このようなタイプのクラスの拡張元のEntityおよびEntityCRUDServiceクラスが、両方ともChangeEventSupportableクラスから拡張されるためです。MAFでサポートされているデータ変更イベントの詳細は、データ変更イベントの使用を参照してください。

データまたはサービス・クラスからデータ変更イベントを送信する必要がある場合は、対応するゲッター・メソッドを呼び出して、変更イベントに送信するインスタンスを取得します。

  • getPropertyChangeSupport()

  • getProviderChangeSupport()

データまたはサービス・クラスにpropertyChangeSupportまたはproviderChangeSupportの独自のインスタンスを含めるのではなく、必ず前述のゲッター・メソッドを使用してください。これにより、MAFアプリケーションのユーザー・インタフェースをリフレッシュするためにMAFクライアント・データ・モデルで使用される、組込みのランタイム・コードが壊れることを防ぎます。

デフォルトでは、各サービス・クラスには、データ・オブジェクトのリストを返すゲッター・メソッドがあります。たとえば、DepartmentServiceクラスには、次のような生成されたメソッドが含まれています。

public List<Department> getDepartment() {
  return getEntityList();
}

MAFアプリケーションでRESTコールを行い、最新の部門リストを取得すると、MAFによって、サービス・クラスのEntityCRUDServiceスーパークラスからsetEntityListメソッドを呼び出すことで自動的にユーザー・インタフェースがリフレッシュされます。このメソッドにより、fireProviderRefreshメソッド・コールで使用されるプロパティ名を見つけるために、サービス・クラス内の別の生成済メソッド(getEntityListName)が呼び出されます。次の例では、DepartmentServiceクラスの、生成されたgetEntityListNameメソッドを示します。

protected String getEntityListName() {
  return "department";
}

前述の実装は、次のことを意味します。

  • 部門リストのコンテンツを変更するカスタム・ロジックを記述する場合は、setEntityListを呼び出して、コンテンツ変更内容でユーザー・インタフェースをリフレッシュできます。

  • 生成されたメソッドgetDepartmentの名前をより適切な複数形名getDepartmentsに変更する場合は、メソッドgetEntityListNameを、departmentではなくdepartmentsを返すよう変更する必要もあります。そうしないと、標準のMAFクライアント・データ・モデル・リフレッシュ・コードが機能しなくなります。

  • データ・オブジェクト・インスタンスのセットに複数のフィルタされたビューを提供するよう、サービス・クラスに独自のゲッター・リスト・メソッドを追加した場合は、RESTコールの完了時にユーザー・インタフェースにおいてフィルタ済リストもリフレッシュされるよう、setEntityListメソッドをオーバーライドできます。詳細は、フィルタされたエンティティ・リストの使用を参照してください。

データ変更イベントへのレスポンスでのフォームのリフレッシュ

データ・オブジェクト・インスタンスが1つのみ表示されるフォーム・レイアウト内のユーザー・インタフェースをリフレッシュするには、プロパティ変更イベントを使用する必要があります。これは、プロバイダ変更イベントではリスト・ビューのみがリフレッシュされるためです。各データ・クラスには、前述のようにプロパティ変更イベントを送信するためにPropertyChangeSupportインスタンスが含まれますが、データ・オブジェクト・インスタンス内の生成されたセッター・メソッドでは、デフォルトでは変更イベントは送信されません。getPropertyChangeSupport()メソッドを使用しさえすれば、自分でこのコードを追加できます。

public void setName(String name)
{
  String oldValue = this.name;
  this.name = name;
  getPropertyChangeSupport().firePropertyChange("name", oldValue, name);;
}

データ・オブジェクト・インスタンスのすべてのプロパティ(属性)をリフレッシュする必要がある場合は、MAFの便利なメソッドEntityUtils.refreshEntityを使用することもできます。これは、その唯一の引数としてデータ・オブジェクト・インスタンスを取ります。

バックグラウンド・スレッドでのデータ変更の送信

バックグラウンド・スレッドでデータ変更イベントを送信する場合、AdfmfJavaUtilities.flushDataChangeEventを呼び出すことで、これらのデータ変更イベントをユーザー・インタフェース・レイヤーにフラッシュする必要があります。さらに、MAFでは、バックグラウンド・スレッドでのデータ変更イベントの送信時のデッドロックを防止するために、MafExecutorServiceを使用することが求められます。次の例では、MafExecutorServiceから実行メソッドを使用して、データ変更イベントを送信し、完了後にイベントをフラッシュする方法を示します。次の例では、Java 8 Lambda式を使用してコードを渡します。

public void setName(String name) {
  String oldValue = this.name;
  this.name = name;
  if (AdfmfJavaUtilities.isBackgroundThread()) {
    MafExecutorService.execute(() ->
       {
         getPropertyChangeSupport().firePropertyChange("name", oldValue, name);
         AdfmfJavaUtilities.flushDataChangeEvent();                     

       });        
  }
  else {
    getPropertyChangeSupport().firePropertyChange("name", oldValue, name);        
  }
}

リフレッシュする属性ごとに前述のコードを記述するかわりに、MAFクライアント・データ・モデルのEntityクラスによって提供されるrefreshUIメソッドを使用して、プロパティ変更イベントを送信できます。このメソッドは、次の例で示すように、データ変更イベントを送信する属性のリストを取ります。

      List<String> attrs = new ArrayList<String>();
      attrs.add("name");
      attrs.add("managerId");
      refreshUI(attrs);

refreshUIメソッドは、前述のMafExecutorServiceを使用し、バックグラウンド・スレッドでの実行時にデータ変更イベントをフラッシュします。

子データ・コレクションからのデータ変更によるユーザー・インタフェースのリフレッシュ

デフォルトでは、親データ・コレクションを返すRESTコールがMAFアプリケーションで実行されるときに、MAFクライアント・データ・モデルで子データ・コレクションへのデータ変更によりユーザー・インタフェースがリフレッシュされることはありません。このデフォルト動作により、RESTコールをトリガーするページに親データ・オブジェクトしか表示される可能性がないときに、子データ・オブジェクトがデータベースから読み取られてメモリーに読み込まれることがなくなるため、アプリケーションのパフォーマンスが最適化されます。データ・オブジェクトのクラス内のEntityクラスからrefreshUIメソッドをオーバーライドすることで、子データ・コレクションを含むようリフレッシュを拡張できます。次の例では、従業員の子データ・コレクションをリフレッシュする必要があるDepartmentクラス内でこれを行う方法を示します。

  @Override
  public void refreshUI(List attrsToRefresh)
  {
    getProviderChangeSupport().fireProviderRefresh("employees");
    super.refreshUI(attrsToRefresh);
  }

6.21 MAFアプリケーションでのオフライン・モードの強制

MAFでは、MAFアプリケーションを、それが実行されているデバイスがインターネットへの接続時にオフラインであるかのように構成できます。

これは、低速なネットワーク接続でのRESTコールを防止するために役立ちます。たとえば、それを使用することで、RESTコールを3G接続では防止し、Wi-Fi接続では許可するようにできます。

オフライン・モードを強制するには、次のメソッドを使用します。

new ConnectivityBean().setForceOffline(true);

注意:

ConnectivityBeanの新しいインスタンスを作成すると同時に、forceOfflineフラグの値が、すべてのインスタンスにわたり共有される、静的変数に保存されます。

これにより、ConnectivityBeanクラスをマネージドBeanとして使用して、ユーザー・インタフェースからオフライン・モードを強制/強制解除できるようになります。これは、MAFのデータ同期機能を示すデモで役立つ可能性があります。これを行うには、次のように、adfc-mobile-config.xmlファイル内でマネージドBeanを定義します。

<managed-bean id="__3">
  <managed-bean-name>Connectivity</managed-bean-name>
  <managed-bean-class>oracle.maf.api.cdm.controller.bean.ConnectivityBean</managed-bean-class>
  <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

その後、次のように、AMXページにオフライン強制トグル・オプションを追加できます。

<amx:commandLink id="menFo" text="#{Connectivity.forceOffline ? 'Unforce offline' : 'Force offline'}">
    <amx:setPropertyListener id="menfospl" from="#{!Connectivity.forceOffline}" to="#{Connectivity.forceOffline}"/>
</amx:commandLink>

MAFユーザー・インタフェース・ジェネレータを使用する方法で説明したとおり、「MAFユーザー・インタフェース・ジェネレータ」ウィザードで、図6-25に示すようにこのオプションを表示するメニュー・エントリを生成します。

図6-25 MAFユーザー・インタフェース・ジェネレータからのオフライン強制メニュー・エントリ

このイメージについては周囲のテキストで説明しています。

ネットワーク接続の程度に基づいてオフライン・モードを強制する必要がある場合は、MAFに事前にインストールされている、Cordovaネットワーク・プラグインを使用して、ConnectivityBean.forceOfflineメソッドを呼び出すJavaScriptコールバック・ハンドラを設定します。

6.22 バックグラウンド・タスクの実行のためのビジュアル・インジケータの使用

エンド・ユーザーが自分のMAFアプリケーションでバックグラウンド・タスクが実行されていることを把握できるようエンド・ユーザーに対してビジュアル・インジケータをレンダリングする方法を説明します。

MAFアプリケーションでスレッド・プール内の1つ以上のタスクが実行されている場合、MAFでは、Booleanフラグを保持する、スレッド・プールを介したすべてのバックグラウンドRESTコールでTrueが返されるようにします。このBooleanフラグの値にアクセスするには、次のEL式を使用します。

#{applicationScope.maf_bgtask_running}

MAFユーザー・インタフェース・ジェネレータを使用する方法で説明したとおり、「MAFユーザー・インタフェース・ジェネレータ」ウィザードにより、MAFアプリケーションでバックグラウンドでタスクが処理されるときに図6-26に示すようにビジュアル・インジケータを表示するよう作成したAMXページに次のエントリを生成します。

  <amx:image id="bgRunImg" source="/images/reloading.gif" inlineStyle="margin-right:5px;" 
            rendered="#{applicationScope.maf_bgtask_running}"/>

図6-26 MAFユーザー・インタフェース・ジェネレータからのバックグラウンド・タスクのためのビジュアル・インジケータ

このイメージについては周囲のテキストで説明しています