ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Application Development Frameworkモバイル開発者ガイド
11g リリース2 (11.1.2.4.0)
B70750-02
  目次へ移動
目次

前
 
次
 

8 バインディングの使用とデータ・コントロールの作成

この章では、ADFモバイル・アプリケーションでデータ・バインディング、データ・コントロールおよびADFデータ・バインディング式言語(EL)を使用する方法と、検証およびデータ変更イベントについて説明します。

この章には次の項が含まれます:

8.1 バインディング・レイヤー・コンポーネントとデータ・コントロールの概要

ADFモデルによって、ユーザー・インタフェース(UI)・テクノロジとビジネス・サービス実装の分離を可能にする2つの概念(データ・コントロール宣言的バインディング)が実装されています。データ・コントロールでは、関連するプロパティ、メソッド、タイプの情報を含め、サービスの操作とデータ・コレクションを表す標準のメタデータ・インタフェースを使用してビジネス・サービスの実装技術を抽象化します。JDeveloperを使用すると、その情報をアイコンとして表示し、ページ上にドラッグ・アンド・ドロップできます。宣言的なバインディングによって、データ・コントロール内のデータ・コレクションからのデータ・アクセスとその操作の実行の詳細が抽象化されます。実行時に、ADFモデル・レイヤーによって、適切なXMLファイルからデータ・コントロールおよびバインディングを記述した情報が読み取られ、ユーザー・インタフェースとビジネス・サービスの双方向の結合が実装されます。

ページのユーザー・インタフェース・コンポーネントをサポートするバインディングのグループは、ページ定義ファイルというページ固有のXMLファイルに記述されます。ADFモデル・レイヤーでは実行時にこのファイルが使用され、ページのバインディングがインスタンス化されます。これらのバインディングは、バインディング・コンテナと呼ばれるリクエスト・スコープ・マップに保持され、EL式#{bindings}を使用して各ページ・リクエスト中にアクセスできます。この式により、現在のページのバインディング・コンテナが常に評価されます。「データ・コントロール」パネルから項目をドラッグし、それを特定のUIコンポーネントとしてページ上にドロップすることで、データバインドされたユーザー・インタフェースを設計できます。データ・コントロールを使用してUIコンポーネントを作成すると、そのコンポーネントを選択したデータ・コントロールにバインドするために必要なコードおよびオブジェクトがJDeveloperによって自動的に作成されます。

ADFモバイルにおけるデータ・コントロールの動作は、Oracle ADFにおける動作と似ています。JDeveloperの「データ・コントロール」パネル内に表示されるDeviceFeaturesデータ・コントロールを使用すると、データ・コントロールの主なデータ属性を(テキスト)フィールドとして、またデータ・コントロールの操作をコマンド・オブジェクト(ボタン)として、アプリケーションにドラッグ・アンド・ドロップできます。これらのドラッグ・アンド・ドロップ・アクションによって、アプリケーション内のELバインディングおよび作成されるコントロールに適したプロパティが生成されます。そのようなアクションに対しては通常のADFバインディングが存在するため、ランタイムでは、アプリケーションの実行時にそれらのバインディングを処理できます。バインディングは、データ・コントロール・ソースを指すために、一般的なDataControls.dcxファイルによって表され、ページ・バインディングによって、特定のページの参照がデータ・コントロールにリンクされます。

データ・バインディングとデータ・コントロールの詳細は、次を参照してください:

8.2 ELサポートの理解

ADFモバイルでは、そのADFモバイルAMXアプリケーション機能での式言語(EL)の使用がサポートされます。ELは、データ・バインディングを有効化するために使用します。ELとOracle ADFの併用の概要については、次の資料を参照してください:

ADF変数とマネージドBean参照は、変数の存続期間と可視性を決定する様々なオブジェクト・スコープ内で定義されます。これらのスコープには、可視性が高い順に、アプリケーション・スコープ、ページ・フロー・スコープおよびビュー・スコープがあります。オブジェクト・スコープのライフサイクルの詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のオブジェクト・スコープのライフサイクルに関する項を参照してください。ADFモバイルでは、次のスコープがサポートされています。

アプリケーション・スコープの名前空間で定義されたEL式は、アプリケーションが存続するかぎり、複数の機能にまたがって使用できます。ADFモバイルを使用すると、アプリケーションの一方のビューでアプリケーション・スコープを定義し、そのスコープをもう一方のビューで参照できます。ページ・フロー・スコープの名前空間で定義されたEL式は、ビューが存続するかぎり、機能の単一ページ内で使用できます。ビュー・フロー・スコープの名前空間で定義されたEL式は、機能が存続するかぎり、単一の機能内で使用できます。このような変数を含むスコープに加えて、ADFモバイルでは、デバイス・プロパティとアプリケーション・プリファレンスに関する情報を公開できるスコープが定義されています。これらのスコープによって、アプリケーション・レベルの存続期間と可視性が決まります。詳細は、第8.2.4.2項「ADFマネージドBean」および第8.2.4.3項「ADFモバイル・オブジェクト」を参照してください。

8.2.1 ADFモバイルAMX ELの実装

ADFモバイルAMX ELの実装は、Java Unified Expression Language (JUEL)プロジェクトに基づき、Expression Language Specification Version 2.1 (http://juel.sourceforge.net/にあるJUELプロジェクトのページで確認できます。今後これを「仕様」と呼びます)に従って行いますが、次のような例外があります。

8.2.1.1 即時および遅延評価

仕様の「1.2.1: Eval-expression」に記載されているとおり、式は即時に評価される場合と遅れて評価される場合があります。ADFモバイルAMX ELの実装では、ページのメタデータをロードするときに式を解析し、ここで解析されたオブジェクトへの参照を所有コンポーネントが保持します。式の評価は、実際にはコンポーネントで値のレンダリングのために式が必要になるまで行われません。ADFモバイルAMXでは遅延セマンティクのみがサポートされるため、即時構成式(${})を使用する式は解析を行いますが、その動作は遅延式(#{})と同じになります。

8.2.1.2 列挙型

仕様の「1.17: Enums」に記載されているとおり、リテラル文字列を使用して列挙型の値に強制することはできません。その理由は、基礎となる必要な列挙操作がJ2MEでサポートされないためです。

8.2.2 バインディング・コンテナを参照する方法

アクティブな画面のバインディング・コンテナは、ルートEL式#{bindings}から参照できます。別の画面のバインディング・コンテナは、式#{data.PageDefName}から参照できます。ADFモバイルAMXバインディング・オブジェクトは、バインディング・コンテナ#{bindings.Name}から名前で参照されます。

表9-1は、実行時にADFモバイルAMXバインディング・オブジェクトの値にアクセスするためのEL式で使用できるプロパティをリストしています。表では、これらのプロパティをアルファベット順にリストしています。

表8-1 実行時プロパティ

実行時プロパティ 説明 イテレータ アクション 属性 ツリー

class

実行時バインディング用のJavaクラス・オブジェクトを戻します。

あり

あり

あり

あり

collectionModel

データのコレクションを公開します。collectionModelにバインドされているコンポーネント内で使用するEL式は、コレクションの各要素の式を解決するrow変数脚注 1 を使用して参照できます。

なし

なし

なし

あり

collectionModel.makeCurrent

このバインディングのイテレータ内で、選択した行を現在の行にします。

なし

なし

なし

あり

collectionModel.selectedRow

選択した行への参照を戻します。

なし

なし

なし

あり

currentRow

イテレータが指している現在の行またはデータ・オブジェクトへの参照を戻します。

あり

なし

なし

なし

currentRow.dataprovider

イテレータが指している現在の行またはデータ・オブジェクトへの参照を戻します。(これはcurrentRowから戻されるものと同じオブジェクトで、構文のみが異なります)。

あり

なし

なし

なし

enabled

アクション・バインディングの状態に応じて、trueまたはfalseを戻します。たとえば、アクション・バインディングは、ユーザーが「先頭へ」、「次へ」、「前へ」、「最後へ」などのナビゲーション・ボタンをクリックした場合に決定される現在位置に基づいて、有効化(true)または無効化(false)されます。

なし

あり

なし

なし

execute

解決されたときに、名前付きアクションまたはmethodActionバインディングを起動します。

なし

あり

なし

なし

format

これはhints.formatのショートカットです。

なし

なし

あり

あり

hints

バインディングが関連付けられているすべての表示属性について、UIヒントの名前/値ペアのリストを戻します。次の名前の付いた値がサポートされています。

  • format: 現在の属性に使用される書式

  • label: 現在の属性に表示されるラベル

  • mandatory: 属性が値セットを保持する必要があるかどうか。

  • precision: 数値属性の表示に使用する精度。

  • updateable: 現在の属性を書き込むことができる場合、trueを戻します。

なし

なし

あり

あり

inputValue

現在の属性の値を戻すか設定します。

なし

なし

あり

なし

items

現在のリストの有効な属性に関連付けられた値のリストを戻します。

なし

なし

あり

なし

label

hintsの子または属性の直接の子として使用できます。バインディングの最初の属性のラベルを戻します(コントロール・ヒントで指定されている場合)。

なし

なし

あり

なし

name

PageDef.xmlファイル内で宣言されたバインディングのidを戻します。

あり

あり

あり

あり

rangeSize

イテレータ・バインディングの行セットの範囲サイズを戻します。

あり

なし

なし

あり

result

メソッド・アクション・バインディングによりバインドおよび起動されるメソッドの結果を戻します。

なし

あり

なし

なし

updateable

hintsの子または属性の直接の子として使用できます。現在の属性が更新可能である場合、trueを戻します。

なし

なし

あり

なし

viewable

Treeの子として使用できます。このバインディングおよび関連コンポーネントをレンダリングするかどうかを実行時に解決します。

なし

なし

なし

あり


脚注 1  EL語句のrowは、コレクション・コンポーネントのコンテキスト内で使用されます。rowは単に、コレクションをレンダリングするときに、ADFモバイルAMXバインディング・オブジェクトからアクセスできる属性を含むコレクションの各要素に対する反復変数として機能します。属性とリスト・バインディングには、row変数を使用してアクセスできます。そのような式の構文は、コレクションに含まれないバインディング・オブジェクトへのアクセスに使用される構文と同じで、#{row.bindings.Name.property}のようにrow変数を先頭の語句として追加します。

8.2.3 ELイベント

ELイベントは、共通語句を含む式が相互に同期して更新できるようにするため、ADFモバイルAMX UIの動作において重要な役割を果たします。

EL式は、様々なコンテキストで値を参照できます。例8-1は、2つの入力数値スライダ・コンポーネントの作成を示しており、各コンポーネントがapplicationScopeの値に関連付けられています。出力テキストでは、ELを使用して単純な追加式を計算結果とともに表示します。フレームワークでは、出力テキスト・ラベル内のEL式を解析するときに、その式に2つの値への参照が含まれていることを確認し、それら2つの値に基づく出力テキストのイベント・リスナー(第7.10項「イベント・リスナーの使用方法」を参照)を作成します。基礎となる式の値が変化すると、イベントがその値のすべてのリスナーに対して生成されます。


注意:

(スコープ・オブジェクトではなく)マネージドBeanのプロパティを参照している場合、リスナーを追加する必要があります。詳細は、第8.2.4.2項「ADFマネージドBean」を参照してください。


例8-1 2つのコンポーネントを含むELイベントの生成

<amx:inputNumberSlider id="slider1" label="X" value="#{applicationScope.X}"/>
<amx:inputNumberSlider id="slider2" label="Y" value="#{applicationScope.Y}"/>
<amx:outputText id="ot1" value="#{applicationScope.X} + 
       #{applicationScope.Y} = #{applicationScope.X + applicationScope.Y}"/>

例8-1では、2つのコンポーネントがそれぞれ1つの値を更新し、1つのコンポーネントが両方の値を使用します。例8-2は、いずれかの既存の値を参照する3つ目の入力数値スライダ・コンポーネントが追加された場合、動作は同じになることを示しています。

例8-2 3つのコンポーネントを含むELイベントの生成

<amx:inputNumberSlider id="slider1" label="X" value="#{applicationScope.X}"/>
<amx:inputNumberSlider id="slider2" label="Y" value="#{applicationScope.Y}"/>
<amx:outputText id="ot1" value="#{applicationScope.X} + 
       #{applicationScope.Y} = #{applicationScope.X + applicationScope.Y}"/>
<amx:inputNumberSlider id="slider3" label="X" value="#{applicationScope.X}"/>

例8-2では、いずれかの入力数値スライダ・コンポーネントが#{applicationScope.X}を更新すると、もう一方が出力テキストとともに自動的に更新されます。

8.2.3.1 構成プロパティ

アプリケーションのadf-config.xmlファイル内にあるすべての<adf-property>要素は、ELを通じて#{applicationScope.configuration}ノードの子として公開されます。このため、たとえばadf-config.xmlが次の例のようになっている場合、#{applicationScope.configuration.key1}の評価によってvalue1が生成され、#{applicationScope.configuration.key2}の評価によってvaue2が生成されます。

<?xml version="1.0" encoding="windows-1252" ?>
<adf-config xmlns="http://xmlns.oracle.com/adf/config" xmlns:config="http://xmlns.oracle.com/bc4j/configuration"
            xmlns:sec="http://xmlns.oracle.com/adf/security/config">
  <adf-properties-child xmlns="http://xmlns.oracle.com/adf/config/properties">
    <adf-property name="key1" value="value1"/>
    <adf-property name="key2" value="value2"/>
  </adf-properties-child>
</adf-config>

また、デバイスでアクセシビリティ・モードが有効になっている場合、#{applicationScope.configuration.accessibilityEnabled}trueと評価されます。iOSデバイスでは、これはVoiceOverがアクティブ化されることを意味します。Androidデバイスでは、これはTalkBackがアクティブ化されることを意味します。

8.2.4 EL式ビルダー

EL式は、JDeveloper式ビルダーで変数と演算子から値を選択することによって作成できます。この式ビルダーは、ELに対応した任意のプロパティの「プロパティ・インスペクタ」から起動できます。式ビルダーの使用の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のADFデータ・バインディングEL式の作成方法に関する項を参照してください。

Oracle ADFには、次の2つのELタイプがあります。

  • 動的EL: ${EL expression}

  • 遅延EL: #{EL expression}

ADFモバイルでは動的ELタイプがサポートされず、${EL expression}#{EL expression}として処理されるため、式を定義するときにハッシュ記号( # )接頭辞を使用する必要があります。詳細は、第8.2.1.1項「即時および遅延評価」を参照してください。

ADFモバイルAMXページの式ビルダーでは、次のカテゴリを使用できます。

8.2.4.1 ADFバインディング

この項では、「ADFバインディング」カテゴリで使用できるオプションをリストします。バインディングとデータ・ノードは、同じ一連のサポートされているバインディングとプロパティを表示します。表8-2に、使用できるバインディング・タイプと、各バインディング・タイプでサポートされるプロパティをリストします。

  • bindings

    表8-2に、使用できるバインディング・タイプと、各バインディング・タイプでサポートされるプロパティをリストします。

  • data

    表8-2に、使用できるバインディング・タイプと、各バインディング・タイプでサポートされるプロパティをリストします。

  • securityContext

    サポートされるプロパティは、次のとおりです。

    • authenticated

    • userGrantedPrivilege

    • userInRole

    • userName

表8-2 サポートされるバインディング・タイプ

バインディング・タイプ プロパティ

accessorIterator

class

currentRow: dataProvider

name

rangeSize

action

classenabled

execute

name

attributeValues

class

format

hints: format, label, updateable

inputValue

items

iteratorBinding

label

name

updateable

button

class

format

hints: format, label, updateable

inputValue

items

label

name

updateable

invokeAction

always

deferred

iterator

class

currentRow: dataProvider

name

rangeSize

list

class

format

hints: format, label, updateable

inputValue

items

label

name

updateable

methodAction

class

enabled

execute

name

operationInfo

paramsMap

result

methodIterator

class

currentRow: dataProvider

name

rangeSize

tree

class

collectionModel: <AttrName>

hints: format, label, updateable, <AttrName>

iteratorBinding

name

rangeSize

viewable

variableIterator

class

currentRow: dataProvider

name


8.2.4.2 ADFマネージドBean

ADFモバイル・アプリケーションでマネージドBeanを作成および使用し、追加のデータを格納したり、カスタム・コードを実行できます。ADFモバイル・アプリケーションへのマネージドBeanの追加は、Fusion WebアプリケーションにマネージドBeanを追加する場合と同じ方法で行います。

詳細は、次を参照してください:

  • 『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のFusion WebアプリケーションでのマネージドBeanの使用方法に関する項。

  • JavaDemo。これはjdev_install/jdeveloper/jdev/extensions/oracle.adf.mobile/Samplesディレクトリ内のADFモバイルのサンプル・アプリケーションです。このサンプル・アプリケーションでは、Java Beanの使用方法とコンテナ・ユーティリティ・メソッドの起動方法を示します。詳細は、付録F「サンプルのADFモバイル・アプリケーション」を参照してください。


注意:

コンポーネントを構成するときは、使用するバインディング・スタイルを十分に考慮してください。より具体的に言うと、標準的なバインディングをマネージドBeanバインディングと組み合せると、解釈を誤った動作が発生することがよくあります。これは、バインディング・インフラストラクチャとマネージドBeanインフラストラクチャとの間でクラス・インスタンスが一致する可能性が低いためです。バインディングが混在すると、UIに直接リンクされていないインスタンスの動作がコールされる場合があります。


サポートされるADFモバイル・マネージドBeanのスコープは、次のとおりです。

  • applicationScope: 「ADFマネージドBean」のapplicationScopeノードには、アプリケーション・レベルで定義されたものがすべて含まれます(アプリケーション・スコープのマネージドBeanなど)。

  • pageFlowScope: 「ADFマネージドBean」のpageFlowScopeノードには、ページ・フロー・レベルで定義されたものがすべて含まれます(ページ・フロー・スコープのマネージドBeanなど)。

  • viewScope: 「ADFマネージドBean」のviewScopeノードには、ビュー・レベルで定義されたものがすべて含まれます(ビュー・スコープのマネージドBeanなど)。

式ビルダーで「ADFマネージドBean」カテゴリを選択すると、「マネージドBeanの作成」ボタンが表示されます。式ビルダーから直接マネージドBeanを作成するには、このボタンをクリックします。

図8-1は、ADFモバイル・マネージドBeanの内容と「マネージドBeanの作成」ボタンの例を示しています。

図8-1 ADFマネージドBeanの内容

ADFモバイル・マネージドBeanの内容

ADFモバイル・ランタイムでは、自身をマネージドBeanプロパティの変更通知のリスナーとして登録することによって、Beanプロパティを参照するUIコンポーネントにバインドされたEL式が、プロパティの値が変更されたときに自動的に更新されるようにします。これらの通知をソースとして参照するには、Beanのプロパティ・アクセッサにコードを追加する必要があります。Beanのプロパティ・アクセッサから、通知をソースとして参照するために必要なコードを自動的に生成するには、「アクセッサの生成」ダイアログの「プロパティの変更時にリスナーに通知」チェック・ボックスを選択します(図8-2を参照)。

図8-2 プロパティの変更時にリスナーに通知

「アクセッサの生成」ダイアログ

ELを通じて単にBeanメソッドまたはプロパティを参照する場合、このコードを追加する必要はありませんが、Beanに格納された値が変化する場合や、特にその変更が、1つ以上のプロパティ値を変更するBeanメソッドの実行による二次的な影響など、間接的なものである場合、それらの値に依存するEL式のアクティブ・フォームへのレンダリングを最新の状態に保つ必要があります。プロパティの変更とPropertyChangeSupportクラスについては、第8.7項「データ変更イベント」を参照してください。


注意:

機能のapplicationScope内でマネージドBeanを宣言し、デザインタイムで別の機能のELを通じてそのBeanを参照しようとすると、そのデザインタイムで無効なELに関する警告が表示されます。この警告は、デザインタイムがそのBeanの現在のプロジェクトで参照を検出できないことが原因で表示されます。そのBeanを実行時に参照できるのは、Beanが宣言されている最初の機能に初めてアクセスし、さらに別の機能のELを通じてアクセスする前にそのBeanをインスタンス化した場合のみです。これは、Name属性の値をノード・ラベルとして使用するPreferenceValue要素には当てはまりません。


例8-3は、プログラムで別のマネージドBean属性にバインドされた値を取得する方法の例を示しています。

例8-3 プログラムでマネージドBeanから取得されるオブジェクト値

public void someMethod()
{
  Object value = AdfmfJavaUtilities.evaluateELExpression("#{applicationScope.MyManagedBean.someProperty}");

例8-4は、プログラムでマネージドBeanからバインディングを実行する方法の例を示しています。

例8-4 プログラムでマネージドBeanから実行されるバインディング

public void someMethod()
{
  Object value = AdfmfJavaUtilities.evaluateELExpression("#{bindings.someDataControlMethod.execute}");

8.2.4.3 ADFモバイル・オブジェクト

ADFモバイル・オブジェクト・カテゴリには、ADFモバイル・フレームワーク内で定義された、ELを使用して参照できる様々なオブジェクト(オブジェクト・スコープなど)がリストされます。ADF変数とマネージドBean参照は、変数の存続期間と可視性を決定する様々なオブジェクト・スコープ内で定義されます。これらのスコープには、可視性が高い順に、アプリケーション・スコープ、ページ・フロー・スコープおよびビュー・スコープがあります。オブジェクト・スコープのライフサイクルの詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のオブジェクト・スコープのライフサイクルに関する項を参照してください。このような変数を含むスコープに加えて、ADFモバイルでは、デバイス・プロパティとアプリケーション・プリファレンスに関する情報を公開できるスコープが定義されます。これらのスコープによって、アプリケーション・レベルの存続期間と可視性が決まります。「ADFモバイル・オブジェクト」カテゴリでは、次のスコープが提供されます。

  • applicationScope: applicationScopeノードには、アプリケーション・レベルで定義されたものがすべて含まれます(アプリケーション・スコープのマネージドBeanなど)。

  • deviceScope: deviceScopeノードには、デバイス・レベルで定義されたものがすべて含まれます(デバイス・スコープのマネージドBeanなど)。ADFモバイルでは、次のdeviceScopeプロパティがサポートされます。

    • device

      • model

      • name

      • os

      • phonegap

      • platform

      • version

    • hardware

      • hasAccelerometer

      • hasCamera

      • hasCompass

      • hasContacts

      • hasFileAccess

      • hasGeolocation

      • hasLocalStorage

      • hasMediaPlayer

      • hasMediaRecorder

      • hasTouchScreen

      • networkStatus

      • screen (availableHeightavailableWidthheightwidth)

  • pageFlowScope: pageFlowScopeノードには、ページ・フロー・レベルで定義されたものがすべて含まれます(ページ・フロー・スコープのマネージドBeanなど)。

  • preferenceScope: preferenceScopeノードには、アプリケーションと機能のすべてのプリファレンスが含まれます。

    • アプリケーションのプリファレンスは、「ADFモバイル・オブジェクト」→「preferenceScope」→「application」で提供されます。

    • 機能のプリファレンスは、「ADFモバイル・オブジェクト」→「preferenceScope」→「feature」→「featureId」で提供されます。

    図8-3は、preferenceScopeノードにあるプリファレンス要素の例を示しています。

    図8-3 preferenceScopeノードのプリファレンス要素

    preferenceScopeノードのプリファレンス要素

    プリファレンス要素では、PreferenceValue要素を除き、Id属性の値を式ビルダーのノード・ラベルとして使用します。PreferenceValue要素では、Name属性の値を式ビルダーのノード・ラベルとして使用します。


    注意:

    EL式の文字列トークンにドット(.)や特殊文字またはdefaultなどの予約語が含まれている場合、式ビルダーではそのような文字列トークンを一重引用符と大カッコで囲みます。機能IDやプリファレンス・コンポーネントIDにドットが含まれている場合、式ビルダーでは、ドットによって区切られたIDの各部分を別のプロパティとしてpreferenceScope階層に表示します。生成された式でも、ドットによって区切られたIDの各部分を別のプロパティとして認識します。


    preferenceScopeのいくつかのサンプルEL式を次に示します。

    例8-5 ドットを含む機能ID

    "#{preferenceScope.feature.oracle.hello.SampleGroup1.label}"
    

    例8-6 属性名が予約語である場合

    "#{preferenceScope.application.OracleMobileApp.Edition['default']}"
    
  • viewScope: このノードには、ビュー・レベルで定義されたものがすべて含まれます(ビュー・スコープのマネージドBeanなど)。

  • row: rowオブジェクトは、collectionModelに含まれる単一のプロバイダへのショートカットである中間変数です。その名前は、親のイテレータ、リスト・ビューまたはカルーセル・コンポーネントのvar属性の値です。このノードでは、次のディレクトリ構造がサポートされます。

    • バインディング

      • AttrName

      • class

      • format

      • hints

      • inputValue

      • items

      • iteratorBinding

      • label

      • name

      • updateable

    • AttrName

      • class

      • format

      • hints

      • inputValue

      • items

      • iteratorBinding

      • label

      • name

      • updateable

    • rowKey

    図8-4は、row変数ノードの内容の例を示しています。

    図8-4 row変数の内容

    row変数の内容の例
  • viewControllerBundle

    これはプロジェクト・レベルで定義されたリソース・バンドルを指すリソース・バンドル変数の名前です。このノードは、amx:loadBundle要素がドロップされ、リソース・バンドルが作成された後にのみ表示されます。このノードの名前は、amx:loadBundleの変数名によって異なります。このノードには、バンドル内で宣言されたすべての文字列が表示されます。

    図8-5は、viewControllerBundleノードの内容の例を示しています。例8-7は、viewControllerBundleのAMXコードの例を示しています。

    図8-5 viewControllerBundleノードの内容

    viewControllerBundleノードの内容

    例8-7 loadBundle要素のAMXコード・サンプル

    <amx:loadBundle basename="mobile.ViewControllerBundle" var="viewcontrollerBundle"/>
    

8.2.4.4 メソッド式ビルダー

表8-3は、「プロパティ・インスペクタ」で「式ビルダー」オプションではなく「メソッド式ビルダー」オプションが提供されるプロパティを示しています。これらの唯一の違いは、メソッド式ビルダーが、選択されたプロパティに応じてマネージドBeanをフィルタして除外することです。

表8-3 編集可能な属性

プロパティ 要素

binding

actionListener

action

commandButton

actionListener

commandButton

action

commandLink

actionListener

commandLink

action

listItem

actionListener

listItem

valueChangeListener

inputDate

valueChangeListener

inputNumberSlider

valueChangeListener

inputText

valueChangeListener

selectBooleanCheckbox

valueChangeListener

selectBooleanSwitch

valueChangeListener

selectManyCheckbox

valueChangeListener

selectManyChoice

valueChangeListener

selectOneButton

valueChangeListener

selectOneChoice

valueChangeListener

selectOneRadio

moveListener

listView


8.2.4.5 非ELプロパティ

表8-4は、ELに対応していないため「プロパティ・インスペクタ」でEL式ビルダーオプションが提供されないプロパティを示しています。

表8-4 非ELプロパティ

プロパティ 要素

name

facet

var

iterator

var

listView

var

loadBundle

group

validationBehavior


8.3 バインディング・レイヤー・コンポーネントの理解

ADFモバイル・ランタイムでは、default動作(例8-8を参照)を使用して特定の操作のアクションを起動します。これは、ページがロードされた後(最初のロードのみではありません)、そのページを繰り返し表示するときに、アクションをコールする必要があるためです。

例8-8 ADFモバイルAMXのinvokeAction

<invokeAction id="callSetCurrentRowWithKeyValue" 
              Binds="setCurrentRowWithKeyValue" 
              Refresh="default" 
              RefreshCondition="#{requestScope.partyId != null}"/>

認識されるRefresh属性の値とそれらの意味については、表8-5「Refreshの値と対応する起動条件」を参照してください。

ADFモバイル・ランタイムでは、実行可能ファイルを起動するための通知の発行に関する次の条件を検出できます。

ランタイムでは、invokeActionを、前述の条件に基づき、そのRefreshおよびRefreshCondition属性の値(表8-5「Refreshの値と対応する起動条件」にリストされています)に従って実行します。詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のRefreshプロパティの正しい使用方法に関する項を参照してください。

表8-5 Refreshの値と対応する起動条件

Refreshの値 起動条件

always: バインディング・コンテナの状態にかかわらず、ページがナビゲートされるたびにinvokeActionを起動します。ランタイムのライフサイクルの観点から言えば、これはsetContextメッセージが毎回送信されるときになります。

AおよびB

deferred: ページにナビゲートし、そのバインディングがロードおよび初期化されたときにinvokeActionを起動します。ランタイムのライフサイクルの観点から言えば、これはバインディング・コンテナを初期化するsetContextメッセージが毎回送信されるときになります。その後のページへのナビゲーションでバインディングがリロードされない場合、アクションは起動しません。デフォルトの動作です。

A

default: デフォルトでは常にdeferredに設定されます。

A


RefreshCondition式が提供された場合、その式はinvokeActionが実行される可能性が生じるたびに評価されます。falseと評価された場合、その発生に対する実行はスキップされます。


注意:

イテレータ実行可能ファイルの場合は、deferredが標準の動作です。イテレータでは、依存するEL式が評価されるまで最初のRefreshを実行しません。ページ定義ファイルのinvokeAction実行可能ファイルのrefresh属性の値はデフォルト(deferred)以外である必要があります。デフォルト値では、リフレッシュおよび起動されません。


ADFモバイルにおけるバインディングの使用の詳細は、次の項を参照してください:

8.3.1 順序付け

デフォルトで、同じRefreshの値を使用して宣言されたinvokeActionは、pagedefで宣言された順序で実行されます。


注意:

先行者が実行されるかどうかは、それぞれのRefreshおよびRefreshConditionの値に基づいて決まります。


8.3.2 ADFモバイルAMXページのELバインディングの検証

ADFモバイルで、ADFモバイルAMXページのELバインディングの検証は、Oracle ADFと同じように動作するJSFページのELの検証と同じメカニズムを使用します。ELの構成はページ・バインディングに対して検証され、メソッドの参照はマネージドBeanに対して検証されます。

検証の詳細は、第8.6項「検証の実行」を参照してください。

8.4 Beanデータ・コントロールの作成と使用

Java Beanデータ・コントロールでは、POJO (Plain Old Java Object)から自身のデータ構造を取得します。Java Beanデータ・コントロールを作成するには、(「アプリケーション」ウィンドウで)Javaクラス・ファイルを右クリックし、「データ・コントロールの作成」を選択します。Beanデータ・コントロールの作成は、EJBデータ・コントロールの作成と非常によく似ています。


注意:

Java Beanがバックグラウンド・スレッドを使用してUI内のデータを更新する場合、手動でoracle.adfmf.framework.api.AdfmfJavaUtilities.flushDataChangeEventをコールする必要があります。flushDataChangeEventメソッドの詳細は、第8.7項「データ変更イベント」を参照してください。


詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のFusion Webアプリケーションのデータ・コントロールに関する項と『Oracle Fusion Middleware Oracle Application Development Framework Java EE開発者ガイド』のADFデータ・コントロールを使用したビジネス・サービスの公開に関する項を参照してください。

8.4.1 Beanクラス変数のシリアライズに関する必知事項

ADFモバイルでは、一時変数として宣言されたJavaScript Object Notation (JSON)データBeanクラス変数にはシリアライズしません。一連のネストされたオブジェクトをシリアライズしないようにするには、それらを一時オブジェクトとして定義する必要があります。この方法を使用すると、オブジェクトのネストが原因で循環オブジェクトが作成されるのを防ぐこともできます。JavaオブジェクトをJSONオブジェクトにシリアライズおよびシリアライズ解除するには、JSONBeanSerializationHelperクラスを使用します。JSONBeanSerializationHelperクラスを使用すると、独自のカスタムJSONシリアライズおよびシリアライズ解除を実装できます。また、このクラスでは、JSONシリアライズ(およびシリアライズ解除)処理後にJSONオブジェクトを変更するためのフックが提供されます。JSONBeanSerializationHelperクラスはGenericTypeSerializationHelperクラスに似ており、RESTおよびSOAPベースのWebサービス内で、GenericTypeオブジェクトのシリアライズおよびシリアライズ解除に使用できます。詳細は、ADFモバイルJavadocのoracle.adfmf.framework.api.JSONBeanSerializationHelperクラスを参照してください。

次のシナリオを考えてみましょう。Employeeオブジェクトが、その子として従業員の上司を表すEmployeeオブジェクトを保持しているとします。その子を一時オブジェクトとして宣言しなかった場合、実行時に子のEmployeeオブジェクトを計算しようとすると、一連のネストされたシリアライズ・オブジェクトが作成されます。

ADFモバイルでは、GregorianCalendarクラスのオブジェクトのシリアライズがサポートされません。JSONBeanSerializationHelperクラスでは、GregorianCalendarクラスのオブジェクトをシリアライズできません。これは、GregorianCalendarクラスに循環参照が含まれるためです。かわりに、java.util.Dateまたはjava.sql.Dateをデータ操作に使用します。次の例は、java.util.Dateを使用してGregorianCalendarオブジェクトを変換する方法を示しています。

Calendar calDate = new GregorianCalendar();
calDate.set(1985, 12, 1); // "January 1, 1986"
Date date = calDate.getTime();

8.5 DeviceFeaturesデータ・コントロールの使用方法

ADFモバイルでは、アプリケーション内でDeviceFeaturersデータ・コントロールを通じて使用できるデバイス固有の機能が公開されます。DeviceFeaturersデータ・コントロールは、新しいADFモバイル・アプリケーションを作成するときに「データ・コントロール」パネルに表示されるコンポーネントです。Cordova Java APIは、このデータ・コントロールを通じて抽象化されます。これにより、ADFモバイルAMXとして実装されたアプリケーション機能から、デバイスに埋め込まれた様々なサービスにアクセスできるようになります。DeviceFeaturesデータ・コントロールから提供される操作をADFモバイルAMXページ内にドラッグ・アンド・ドロップすることによって、デバイスに格納されたユーザーのコンタクト先を管理する機能の追加、電子メール・メッセージとSMSテキスト・メッセージの両方の作成と送信、デバイスの位置の確認、デバイスのカメラの使用およびデバイスのファイル・システムに格納されたイメージの取得を行うことができます。次の項では、これらの操作を宣言的に使用する方法や、JavaコードとJavaScriptを使用して実装する方法など、各操作について詳しく説明します。

図8-6 「概要」エディタでのADFモバイルのDeviceFeaturesデータ・コントロール

JDeveloperでのADFモバイルのDeviceFeaturesデータ・コントロール

ADFモバイル・アプリケーション・テンプレートを使用してアプリケーションを作成すると、自動的にDeviceFeaturesデータ・コントロールが「データ・コントロール」パネルに表示されます。図8-6は、「概要」エディタ内のDeviceFeaturesデータ・コントロールを示しています。次のメソッドを使用できます。

ページを作成したら、DeviceFeaturesデータ・コントロールのメソッド(またはそれらのメソッド内にネストされたその他のオブジェクト)を「データ・コントロール」パネルから「ADFモバイルAMX」ビューにドラッグして、関連する機能にバインドされたコマンド・ボタンやその他のコンポーネントを作成できます。デフォルトのバインディングを受け入れるか、ELを使用してそれらのバインディングを変更できます。また、JavaScriptやJavaを使用して、機能を実装または構成することもできます。

DeviceManagerは、デバイスの機能へのアクセスを可能にするオブジェクトです。このオブジェクトのハンドルは、DeviceManagerFactory.getDeviceManagerをコールすることによって取得できます。次の項では、DeviceManagerオブジェクトを使用してgetPicturecreateContactなどのメソッドを起動する方法について説明します。

データ・コントロールをADFモバイル・アプリケーションに含める方法については、第6.3.2.4項「データ・コントロールのビューへの追加」を参照してください。

8.5.1 getPictureメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるgetPictureメソッドをADFモバイル・アプリケーションで使用すると、デバイスのカメラとフォト・ライブラリを活用し、エンド・ユーザーが写真を撮影したり、既存のイメージを取得できるようにすることが可能です。例8-9は、エンド・ユーザーがデバイスのカメラを使用して写真を撮影することを可能にするJavaScriptコードを示しています。例8-10例8-11は、エンド・ユーザーが写真を撮影したり、保存済イメージを取得することを可能にするJavaコードを示しています。getPictureメソッドについては、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

次のパラメータによって、イメージの取得元と、そのイメージを戻す方法が制御されます。

  • quality: 保存済イメージの質を設定します。範囲は1から100 (100を含む)です。大きい数値を指定すると質は高くなりますが、ファイル・サイズも増大します。JPEGイメージ(encodingTypeで指定します)にのみ適用されます。

  • destinationType: 戻り値の形式を次から選択します。

    • DeviceManager.CAMERA_DESTINATIONTYPE_DATA_URL (0): Base64でエンコードされた文字列としてイメージを戻します。この値は、プログラムで使用される場合、DeviceManager.CAMERA_DESTINATION_DATA_URLを使用する列挙としても指定されます。イメージをイメージ・コンポーネント内に表示するには、戻された値の前にdata:image/gif;base64を付ける必要があります。

    • DeviceManager.CAMERA_DESTINATIONTYPE_FILE_URI (1): イメージ・ファイルのパスを戻します。この値は、プログラムで使用される場合、DeviceManager.CAMERA_DESTINATION_FILE_URIを使用する列挙としても指定されます。

  • sourceType: 写真のソースを次から選択して設定します。

    • DeviceManager.CAMERA_SOURCETYPE_PHOTOLIBRARY (0): ユーザーは保存済のイメージから選択できます。この値は、プログラムで使用される場合、DeviceManager.CAMERA_SOURCETYPE_PHOTOLIBRARYを使用する列挙としても指定されます。

    • DeviceManager.CAMERA_SOURCETYPE_CAMERA (1): ユーザーはデバイスのカメラを使用して写真を撮影できます。この値は、プログラムで使用される場合、DeviceManager.CAMERA_SOURCETYPE_CAMERAを使用する列挙としても指定されます。

    • DeviceManager.CAMERA_SOURCETYPE_SAVEDPHOTOALBUM (2): ユーザーは既存のフォト・アルバムから選択できます。この値は、プログラムで使用される場合、DeviceManager.CAMERA_SOURCETYPE_SAVEDPHOTOALBUMを使用する列挙としても指定されます。

  • allowEdit: 選択する前にイメージの単純な編集を許可するかどうかを選択します(ブール)。

  • encodingType: 戻されるイメージ・ファイルのエンコーディングを次から選択します。

    • DeviceManager.CAMERA_ENCODINGTYPE_JPEG (0): 戻されるイメージをJPEGファイルとしてエンコードします。この値は、プログラムで使用される場合、DeviceManager.CAMERA_ENCODINGTYPE_JPEGを使用する列挙としても指定されます。

    • DeviceManager.CAMERA_ENCODINGTYPE_PNG (1): 戻されるイメージをPNGファイルとしてエンコードします。この値は、プログラムで使用される場合、DeviceManager.CAMERA_ENCODINGTYPE_PNGを使用する列挙としても指定されます。

  • targetWidth: 幅をピクセル単位で設定してイメージのスケールを変更します。アスペクト比は維持されます。負の値または0の場合、イメージの元のディメンションが使用されます。

  • targetHeight: 高さをピクセル単位で設定してイメージのスケールを変更します。アスペクト比は維持されます。負の値または0の場合、イメージの元のディメンションが使用されます。

DeviceFeaturesデータ・コントロールを使用してgetPicture操作をカスタマイズするには:

  1. 「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからgetPicture操作をドラッグし、ADFモバイルのボタンとしてページにドロップします。

    ユーザーがよりきめ細かく制御できるようにするには、getPicture操作をADFモバイルのパラメータ・フォームとしてドロップします。これにより、エンド・ユーザーは写真を撮影したり既存のイメージを選択する前に、設定を指定できるようになります。

  2. アクションの編集ダイアログで、前述のすべてのパラメータの値を設定します。イメージがファイル名として戻されるように、destinationType = 1を指定するようにします。

  3. getPictureの戻り値をドラッグし、それを出力テキストとしてページ上にドロップします。

  4. 「共通コンポーネント」パネルで、「コンポーネント・パレット」から「イメージ」をドラッグし、ページ上にドロップします。

  5. イメージのsource属性を、getPicture操作の戻り値に設定します。バインディングの式は、#{bindings.Return.inputValue}である必要があります。

図8-7は、エンド・ユーザーのフォト・ライブラリからイメージを表示するためのバインディングを示しています。

図8-7 デザインタイムでフォト・ライブラリからイメージを表示するためのバインディング

getPictureメソッドのバインディング

このアプリケーションを実行すると、イメージ・チューザが自動的に表示され、エンド・ユーザーは表示するイメージを選択できます。イメージ・チューザが自動的に表示される理由は、イメージ・コントロールがgetPicture操作の戻り値にバインドされており、それによってgetPicture操作が起動するためです。

次に示すプラットフォーム固有の問題に留意してください。

  • iOS

    • いくつかのデバイスでメモリー・エラーが発生しないようにするには、qualityを50未満に設定します。

    • destinationType FILE_URIを使用すると、写真はアプリケーションの一時ディレクトリに保存されます。

    • アプリケーションの一時ディレクトリの内容は、アプリケーションの終了時に削除されます。記憶域の空き領域が問題になる場合は、navigator.fileMgr APIを使用してこのディレクトリの内容を削除することもできます。

    • targetWidthtargetHeightを使用するには、これらを両方とも指定する必要があります。一方または両方の値が負の値または0の場合、イメージの元のディメンションが使用されます。

  • Android

    • allowEditパラメータを無視します。

    • Camera.PictureSourceType.PHOTOLIBRARYCamera.PictureSourceType.SAVEDPHOTOALBUMでは、どちらも同じフォト・アルバムが表示されます。

    • Camera.EncodingTypeはサポートされていません。パラメータは無視され、常にJPEGイメージが生成されます。

    • targetWidthtargetHeightは、個別に指定できます。一方のパラメータが正の値で、もう一方が負の値またはゼロを使用して元のサイズを表す場合、正の値がそのディメンションに使用され、もう一方のディメンションは元のアスペクト比を維持するようにスケール変更されます。

    • destinationType DATA_URLを使用すると、イメージが大きい場合は使用可能なメモリーがすべて使用され、メモリー不足のエラーが発生する場合があります。通常は、デフォルトのイメージ・サイズを使用すると、この動作が発生します。targetWidthtargetHeightを設定してイメージ・サイズを制限します。

例8-9は、ユーザーがデバイスのカメラを使用して写真を撮影することを可能にするJavaScriptコードを示しています。結果は、保存済イメージへのフルパスになります。

例8-9 getPictureのJavaScriptコード例

// The camera, like many other device-specific features, is accessed 
// from the global 'navigator' object in JavaScript.
// Note that in the Cordova JavaScript APIs, the parameters are passed
// in as a dictionary, so it is only necessary to provide key-value pairs
// for the parameters you want to specify.

navigator.camera.getPicture(onSuccess, onFail, { quality: 50 });

function onSuccess(imageURI) { 
    var image = document.getElementById('myImage');
    image.src = imageURI;
}
function onFail(message) {
    alert('Failed because: ' + message);
}

例8-10は、ユーザーがデバイスのカメラを使用して写真を撮影することを可能にするJavaコードを示しています。結果は、保存済イメージへのフルパスになります。

例8-10 getPictureを使用して写真を撮影するためのJavaコード例

import oracle.adf.model.datacontrols.device; 

// Access device features in Java code by acquiring an instance of the  
// DeviceManager from the DeviceManagerFactory.
// Take a picture with the device's camera.  
// The result will be the full path to the saved PNG image.
String imageFilename = DeviceManagerFactory.getDeviceManager().getPicture(100,
    DeviceManager.CAMERA_DESTINATIONTYPE_FILE_URI,
    DeviceManager.CAMERA_SOURCETYPE_CAMERA, false,
    DeviceManager.CAMERA_ENCODINGTYPE_PNG, 0, 0);

例8-11は、ユーザーが保存済イメージを取得することを可能にするJavaコードを示しています。結果は、Base64でエンコードされたJPEGになります。

例8-11 getPictureを使用してイメージを取得するためのJavaコード例

import oracle.adf.model.datacontrols.device; 

// Retrieve a previously-saved image. The result will be a base64-encoded JPEG.
String imageData = DeviceManagerFactory.getDeviceManager().getPicture(100, 
  DeviceManager.CAMERA_DESTINATIONTYPE_FILE_URL,
  DeviceManager.CAMERA_SOURCETYPE__PHOTOLIBRARY, false,
  DeviceManager.CAMERA_ENCODINGTYPE_JPEG, 0, 0);

8.5.2 SendSMSメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるsendSMSメソッドをADFモバイル・アプリケーションで使用すると、デバイスのショート・メッセージ・サービス(SMS)テキスト・メッセージング・インタフェースを活用し、エンド・ユーザーがSMSメッセージを送受信できるようにすることが可能です。ADFモバイルでは、デバイスのSMSインタフェースを表示し、必要に応じて次のフィールドに事前にデータを移入できます。

  • to: 受信者をリストします(カンマ区切り)。

  • body: メッセージの本文を追加します。

SMSテキスト・メッセージング・インタフェースが表示されたら、エンド・ユーザーはSMSを送信するか、それを取り消すことができます。デバイスとキャリアの制限により、SMSは自動的に送信できません。実際にSMSを送信できるのは、エンド・ユーザーのみです。

DeviceFeaturesデータ・コントロールを使用してsendSMS操作をカスタマイズするには:

SMSの送信のためページに対話型フォームを表示するには、sendSMS操作を「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからドラッグし、ページ・デザイナ上にADFモバイルのパラメータ・フォームとしてドロップします。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。実行時に、アプリケーション・ユーザーが前述の様々なフィールドの値を入力できる、編集可能なフォームがページに表示されます。このフォームの下にあるボタンを使用すると、デバイスのSMSインタフェースを表示できます。このインタフェースには、指定したすべてのフィールドに事前に値が移入され、送信準備が整ったSMSが表示されます。

図8-8は、ページ上の編集可能なフォームを使用してSMSを送信するためのバインディングを示しています。

図8-8 デザインタイムで編集可能なフォームを使用してSMSを送信するためのバインディング

sendSMSメソッドのバインディング

例8-12例8-13は、エンド・ユーザーがデバイスのテキスト・メッセージング・インタフェースを使用してSMSメッセージを送信することを可能にするコード例を示しています。

sendSMSメソッドについては、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

例8-12 sendSMSのJavaScriptコード例

adf.mf.api.sendSMS({to: "5551234567", body: "This is a test message"}); 

例8-13 sendSMSのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

// Access device features in Java code by acquiring an instance of the  
// DeviceManager from the DeviceManagerFactory.
// Send an SMS to the phone number "5551234567"
DeviceManagerFactory.getDeviceManager().sendSMS("5551234567", "This is a test message");

8.5.3 sendEmailメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるsendEmailメソッドをADFモバイル・アプリケーションで使用すると、デバイスの電子メール・メッセージング・インタフェースを活用し、エンド・ユーザーが電子メール・メッセージを送受信できるようにすることが可能です。ADFモバイルでは、デバイスの電子メール・インタフェースを表示し、必要に応じて次のフィールドに事前にデータを移入できます。

  • to: 受信者をリストします(カンマ区切り)。

  • cc: CC受信者をリストします(カンマ区切り)。

  • subject: メッセージの件名を追加します。

  • body: メッセージの本文を追加します。

  • bcc: BCC受信者をリストします(カンマ区切り)。

  • attachments: 電子メールに添付するファイルの名前をリストします(カンマ区切り)。

  • mimeTypes: 添付ファイルに使用するMIMEタイプをリストします(カンマ区切り)。ADFモバイルで自動的にMIMEタイプを決定するには、nullを指定します。例8-14例8-15のように、選択した添付ファイルのMIMEタイプのみを指定することもできます。

デバイスの電子メール・インタフェースが表示されたら、ユーザーは電子メールを送信するか、それを取り消すことができます。デバイスとキャリアの制限により、電子メールは自動的に送信できません。実際に電子メールを送信できるのは、エンド・ユーザーのみです。また、電子メールを送信するには、1つ以上の電子メール・アカウントを構成する必要があります。アカウントが構成されていない場合、電子メール・アカウントが見つからないことを示すエラーが表示されます。

DeviceFeaturesデータ・コントロールを使用してsendEmail操作をカスタマイズするには:

JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからsendEmail操作をページ・デザイナ上にドラッグし、ADFモバイルのパラメータ・フォームとしてドロップします。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。実行時に、アプリケーション・ユーザーが前述の様々なフィールドの値を入力できる、編集可能なフォームがページに表示されます。このフォームの下にあるボタンを使用すると、デバイスの電子メール・インタフェースを表示できます。このインタフェースには、指定したすべてのフィールドに事前に値が移入され、送信準備が整った電子メールが表示されます。

図8-9は、ページ上の編集可能なフォームを使用して電子メールを送信するためのバインディングを示しています。

図8-9 デザインタイムで編集可能なフォームを使用して電子メールを送信するためのバインディング

sendEmailメソッドのバインディング

例8-14例8-15は、エンド・ユーザーがデバイスの電子メール・インタフェースを使用して電子メール・メッセージを送信することを可能にするコード例を示しています。

sendEmailメソッドについては、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

例8-14 sendEmailのJavaScriptコード例

// Populate an email to 'ann.li@example.com',  
// copy 'joe.jones@example.com', with the 
// subject 'Test message', and the body 'This is a test message'
// No BCC recipients or attachments
adf.mf.api.sendEmail({to: "ann.li@example.com",
                           cc: "joe.jones@example.com",
                           subject: "Test message",
                           body: "This is a test message"});

// Populate the same email as before, but this time, also BCC 
// 'john.smith@example.com' & 'jane.smith@example.com' and attach two files.
// By not specifying a value for the mimeTypes parameter, you are telling 
// ADFMobile to automatically determine the MIME type for each of the attachments.
adf.mf.api.sendEmail({to: "ann.li@example.com",
                           cc: "joe.jones@example.com",
                           subject: "Test message",
                           body: "This is a test message"});
                           bcc: "john.smith@example.com,jane.smith@example.com",
                           attachments: "path/to/file1.txt,path/to/file2.png"});

// For iOS only: Same as previous email, but this time, explicitly specify
// all the MIME types.
adf.mf.api.sendEmail({to: "ann.li@example.com",
                           cc: "joe.jones@example.com",
                           subject: "Test message",
                           body: "This is a test message"});
                           bcc: "john.smith@example.com,jane.smith@example.com",
                           attachments: "path/to/file1.txt,path/to/file2.png"});
                           mimeTypes: "text/plain,image/png"});

// For iOS only: Same as previous email, but this time, only specify  
// the MIME type for the second attachment and let the system determine
// the MIME type for the first one.
adf.mf.api.sendEmail({to: "ann.li@example.com",
                           cc: "joe.jones@example.com",
                           subject: "Test message",
                           body: "This is a test message"});
                           bcc: "john.smith@example.com,jane.smith@example.com",
                           attachments: "path/to/file1.txt,path/to/file2.png"});
                           mimeTypes: ",image/png"});

// For Android only: Same as previous e-mail, but this time, explicitly specify 
// the MIME type.
adf.mf.api.sendEmail({to: "ann.li@example.com",
                           cc: "joe.jones@example.com",
                           subject: "Test message",
                           body: "This is a test message"});
                           bcc: "john.smith@example.com,jane.smith@example.com",
                           attachments: "path/to/file1.txt,path/to/file2.png"});
                           mimeTypes: "image/*"}); 
// You can also use "plain/text" as the MIME type as it just determines the type
// of applications to be filtered in the application chooser dialog.

例8-15 sendEmailのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

// Access device features in Java code by acquiring an instance of the  
// DeviceManager from the DeviceManagerFactory.
// Populate an email to 'ann.li@example.com', copy 'joe.jones@example.com', with the 
// subject 'Test message', and the body 'This is a test message'.
// No BCC recipients or attachments.
DeviceManagerFactory.getDeviceManager().sendEmail(
                                        "ann.li@example.com",
                                        "joe.jones@example.com",
                                        "Test message",
                                        "This is a test message",
                                        null,
                                        null,
                                        null);

// Populate the same email as before, but this time, also BCC 
// 'john.smith@example.com' & 'jane.smith@example.com' and attach two files.
// By specifying null for the mimeTypes parameter, you are telling 
// ADFMobile to automatically determine the MIME type for each of the attachments.
DeviceManagerFactory.getDeviceManager().sendEmail(
                                        "ann.li@example.com",
                                        "joe.jones@example.com",
                                        "Test message",
                                        "This is a test message",
                                        "john.smith@example.com,jane.smith@example.com",
                                        "path/to/file1.txt,path/to/file2.png",
                                        null);

// Same as previous email, but this time, explicitly specify all the MIME types.
DeviceManagerFactory.getDeviceManager().sendEmail(
                                        "ann.li@example.com",
                                        "joe.jones@example.com",
                                        "Test message",
                                        "This is a test message",
                                        "john.smith@example.com,jane.smith@example.com",
                                        "path/to/file1.txt,path/to/file2.png",
                                        "text/plain,image/png");


// Same as previous email, but this time, only specify the MIME type for the 
// second attachment and let the system determine the MIME type for the first one.
DeviceManagerFactory.getDeviceManager().sendEmail(
                                        "ann.li@example.com",
                                        "joe.jones@example.com",
                                        "Test message",
                                        "This is a test message",
                                        "john.smith@example.com,jane.smith@example.com",
                                        "path/to/file1.txt,path/to/file2.png",
                                        ",image/png");

8.5.4 createContactメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるcreateContactメソッドをADFモバイル・アプリケーションで使用すると、デバイスのコンタクト先を管理するためのインタフェースとファイル・システムを活用し、エンド・ユーザーが新しいコンタクト先を作成してデバイスのアドレス帳に保存できるようにすることが可能です。ADFモバイルでは、デバイスのインタフェースを表示し、必要に応じてContactのフィールドに事前にデータを移入できます。例8-17のように、createContactメソッドはContactオブジェクトをパラメータとして使用し、作成されたContactオブジェクトを戻します。

createContactメソッドとContactオブジェクトの詳細は、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。Contactのプロパティについては、第8.5.5項「findContactsメソッドの使用方法」も参照してください。

DeviceFeaturesデータ・コントロールを使用してcreateContact操作をカスタマイズするには:

  1. JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからcreateContact操作をドラッグし、ADFモバイルのリンクまたはボタンとしてページ・デザイナ上にドロップします。

    リンクまたはボタン: 「アクション・バインディングの編集」ダイアログが表示され、createContact操作に対するContactオブジェクトのパラメータを入力するよう求められます。このパラメータは、Java BeanクラスからContactを戻すために使用されるマネージドBeanのプロパティを参照するEL式である必要があります。マネージドBeanにContactオブジェクトのゲッターがすでに含まれている場合は、EL式ビルダーを使用して、パラメータの値を設定できます。実行時にページに表示されるボタンまたはリンクをクリックすると、入力した値を使用してcreateContact操作を実行できます。例8-16は、Contactオブジェクトを作成するためのマネージドBeanコードの例を示しています。

  2. 戻されたContactオブジェクトを「データ・コントロール」パネルにあるcreateContact操作の下からドラッグし、ADFフォームとしてページ上にドロップすることもできます。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。createContact操作を実行すると、結果がこのフォームに表示されます。

例8-16 Contactオブジェクトを作成するためのマネージドBeanコード

private Contact contactToBeCreated;
 
public void setContactToBeCreated(Contact contactToBeCreated)
{
   this.contactToBeCreated = contactToBeCreated;
}
 
public Contact getContactToBeCreated()
{
   String givenName = "Mary";
   String familyName = "Jones";
   String note = "Just a Note";
   String phoneNumberType = "mobile";
   String phoneNumberValue = "650-555-0111";
   String phoneNumberNewValue = "650-555-0199";
   String emailType = "home";
   String emailTypeNew = "work";
   String emailValue = "Mary.Jones@example.com";
   String addressType = "home";
   String addressStreet = "500 Barnacle Pkwy";
   String addressLocality = "Redwood Shores";
   String addressCountry = "USA";
   String addressPostalCode = "94065";
   ContactField[] phoneNumbers = null;
   ContactField[] emails = null;
   ContactAddresses[] addresses = null;
 
   /*
    * Create contact
    */
   this.contactToBeCreated = new Contact();
 
   ContactName name = new ContactName();
   name.setFamilyName(familyName);
   name.setGivenName(givenName);
   this.contactToBeCreated.setName(name);
 
   ContactField phoneNumber = new ContactField();
   phoneNumber.setType(phoneNumberType);
   phoneNumber.setValue(phoneNumberValue);
 
   phoneNumbers = new ContactField[] { phoneNumber };
 
   ContactField email = new ContactField();
   email.setType(emailType);
   email.setValue(emailValue);
 
   emails = new ContactField[] { email };
 
   ContactAddresses address = new ContactAddresses();
   address.setType(addressType);
   address.setStreetAddress(addressStreet);
   address.setLocality(addressLocality);
   address.setCountry(addressCountry);
 
   addresses = new ContactAddresses[] { address };
 
   this.contactToBeCreated.setNote(note);
   this.contactToBeCreated.setPhoneNumbers(phoneNumbers);
   this.contactToBeCreated.setEmails(emails);
   this.contactToBeCreated.setAddresses(addresses);
 
   return this.contactToBeCreated;
}

例8-17例8-18は、エンド・ユーザーがデバイスにコンタクト先を作成することを可能にするコード例を示しています。

例8-17 createContactのJavaScriptコード例

// Contacts, like many other device-specific features, are accessed from the global 'navigator' object in JavaScript.
var contact = navigator.contacts.create();
 
var name = new ContactName();
name.givenName = "Mary";
name.familyName = "Jones";
 
contact.name = name;
 
// Store contact phone numbers in ContactField[]
var phoneNumbers = [1];
phoneNumbers[0] = new ContactField('home', '650-555-0123', true);
 
contact.phoneNumbers = phoneNumbers;
 
// Store contact email addresses in ContactField[]
var emails = [1];
emails[0] = new ContactField('work', 'Mary.Jones@example.com');
 
contact.emails = emails;
 
// Save
contact.save(onSuccess, onFailure);
 
function onSuccess()
{
  alert("Create Contact successful.");
}
 
function onFailure(Error)
{
  alert("Create Contact failed: " + Error.code);
}
     

例8-18 createContactのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory; 

import oracle.adf.model.datacontrols.device.ContactAddresses;
import oracle.adf.model.datacontrols.device.ContactField;
import oracle.adf.model.datacontrols.device.ContactName;

String givenName = "Mary";
String familyName = "Jones";
String note = "Just a Note";
String phoneNumberType = "mobile";
String phoneNumberValue = "650-555-0111";
String phoneNumberNewValue = "650-555-0199";
String emailType = "home";
String emailTypeNew = "work";
String emailValue = "Mary.Jones@example.com";
String addressType = "home";
String addressStreet = "500 Barnacle Pkwy";
String addressLocality = "Redwood Shores";
String addressCountry = "USA";
String addressPostalCode = "91234";
ContactField[] phoneNumbers = null;
ContactField[] emails = null;
ContactAddresses[] addresses = null;
ContactField[] emails = null;
    
/*
* Create contact
*/
Contact aContact = new Contact();
     
ContactName name = new ContactName();
name.setFamilyName(familyName);
name.setGivenName(givenName);
aContact.setName(name);
     
ContactField phoneNumber = new ContactField();
phoneNumber.setType(phoneNumberType);
phoneNumber.setValue(phoneNumberValue);
     
phoneNumbers = new ContactField[] { phoneNumber };
     
ContactField email = new ContactField();
email.setType(emailType);
email.setValue(emailValue);
     
emails = new ContactField[] { email };
     
ContactAddresses address = new ContactAddresses();
address.setType(addressType);
address.setStreetAddress(addressStreet);
address.setLocality(addressLocality);
address.setCountry(addressCountry);
     
addresses = new ContactAddresses[] { address };
     
aContact.setNote(note);
aContact.setPhoneNumbers(phoneNumbers);
aContact.setEmails(emails);
aContact.setAddresses(addresses);
     
// Access device features in Java code by acquiring an instance of the  
// DeviceManager from the DeviceManagerFactory.
// Invoking the createContact method, using the DeviceDataControl object.
Contact createdContact = DeviceManagerFactory.getDeviceManager()
    .findContacts.createContact(aContact);
     

8.5.5 findContactsメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるfindContactsメソッドをADFモバイル・アプリケーションで使用すると、デバイスのコンタクト先を管理するためのインタフェースとファイル・システムを活用し、エンド・ユーザーがデバイスのアドレス帳から1つ以上のコンタクト先を検索できるようにすることが可能です。ADFモバイルでは、デバイスのインタフェースを表示し、必要に応じてfindContactsのフィールドに事前にデータを移入できます。findContactsメソッドでは、フィルタ文字列と検索する(そして、見つかったコンタクト先の一部として戻す)フィールド名のリストを使用します。フィルタ文字列には、コンタクト先内の検索する任意の項目を指定できます。findContactsメソッドの詳細は、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

findContacts操作では、次の引数を使用します。

  • contactFields: 必須パラメータ。このパラメータは、findContacts操作によって生成されるContactオブジェクトに含めるフィールドを指定するために使用します。フィールドはカンマで区切ります(スペースの有無は関係ありません)。

  • filter: コンタクト先をフィルタするために使用する検索文字列。(文字列) (デフォルト: "")

  • multiple: findContacts操作から複数のコンタクト先を戻すかどうかを決定します。(ブール) (デフォルト: false)


注意:

次のリストに含まれていないフィールド名を渡すと、findContacts操作の戻り値がnullになる場合があります。また、Contactのフィールドの引数に指定したフィールドのみが、Contactオブジェクトの一部として戻されます。


次のリストに示すContactのプロパティを渡して、検索に使用し、見つかったコンタクト先の一部として戻すことができます。

  • id: グローバルに一意な識別子

  • displayName: エンド・ユーザーへの表示に適した、このコンタクト先の名前

  • name: 人物名のすべてのコンポーネントを含むオブジェクト

  • nickname: コンタクト先のカジュアルな名前

  • phoneNumbers: コンタクト先のすべての電話番号の配列

  • emails: コンタクト先のすべての電子メール・アドレスの配列

  • addresses: コンタクト先のすべての住所の配列

  • ims: すべてのインスタント・メッセージング(IM)アドレスの配列(imsプロパティは、このリリースではサポートされていません。)

  • organizations: コンタクト先のすべての組織の配列

  • revision: コンタクト先が最後に訂正された日付

  • birthday: コンタクト先の誕生日

  • gender: コンタクト先の性別

  • note: コンタクト先に関するメモ

  • photos: コンタクト先の写真の配列

  • urls: コンタクト先に関連付けられたWebページの配列

DeviceFeaturesデータ・コントロールを使用してfindContacts操作をカスタマイズするには:

  1. JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからfindContacts操作をドラッグし、ADFモバイルのリンクボタンまたはパラメータ・フォームとしてページ・デザイナ上にドロップします。

    リンクまたはボタン: 「アクション・バインディングの編集」ダイアログが表示され、findContacts操作の引数の値を入力するよう求められます。実行時にページに表示されるボタンまたはリンクをクリックすると、入力した値を使用してfindContacts操作を実行できます。

    パラメータ・フォーム: 「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズします。実行時に、アプリケーション・ユーザーが前述のContactの様々なフィールドの値を入力できる、編集可能なフォームがページに表示されます。このフォームの下にあるボタンをクリックすると、入力した値を使用してfindContacts操作を実行できます。

  2. 戻されたContactオブジェクトを「データ・コントロール」パネルにあるfindContacts操作の下からドラッグし、ADFフォームとしてページ上にドロップすることもできます。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。findContacts操作を実行すると、結果がこのフォームに表示されます。

例8-19は、findContactsメソッドに指定できる引数値を示しています。例8-20例8-21は、姓でコンタクト先を検索し、コンタクト先の名前、電話番号、電子メール、住所およびメモを取得する方法を示しています。

例8-19 findContactsに指定できる引数値

// This will return just one contact with only the ID field:
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts("", "", false);

// This will return all contacts with only ID fields:
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts("", "", true);

// This will return just one contact with all fields:
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts("*", "", false);

// This will return all contacts with all fields:
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts("*", "", true);

// These will throw an exception as contactFields is a required argument and cannot be null:
DeviceManagerFactory.getDeviceManager().findContacts(null, "", false);
DeviceManagerFactory.getDeviceManager().findContacts(null, "", true);

// These will throw an exception as the filter argument cannot be null:
DeviceManagerFactory.getDeviceManager().findContacts("", null, false);
DeviceManagerFactory.getDeviceManager().findContacts("", null, true);

注意:

渡されるContactのフィールドは、文字列(カンマで区切られたフィールドを含む)です。いずれかの引数がnullとしてメソッドに渡された場合、ADFの例外がスローされます。


例8-20 findContactsのJavaScriptコード例

var filter = ["name", "phoneNumbers", "emails", "addresses", "note"];
 
var options = new ContactFindOptions();
options.filter="FamilyName";
 
// Contacts, like many other device-specific features, are accessed from 
// the global 'navigator' object in JavaScript.
navigator.contacts.find(filter, onSuccess, onFail, options);
 
function onSuccess(contacts)
{
  alert ("Find Contact call succeeded! Number of contacts found = " + contacts.length);
}
 
function onFail(Error)
{
  alert("Find Contact failed: " + Error.code);
}

例8-21 findContactsのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

/*
 * Find Contact - Find contact by family name.
 *
 * See if we can find the contact that we just created.
 */

String familyName = "FamilyName"

// Access device features in Java code by acquiring an instance of the  
// DeviceManager from the DeviceManagerFactory.
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts(
    "name,phoneNumbers,emails,addresses,note", familyName, true); 

8.5.6 updateContactメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるupdateContactメソッドをADFモバイル・アプリケーションで使用すると、コンタクト先を管理するためにデバイスのインタフェースとファイル・システムを活用し、エンド・ユーザーがデバイスのアドレス帳に含まれるコンタクト先を更新できるようにすることが可能です。ADFモバイルでは、デバイスのインタフェースを表示し、必要に応じてupdateContactのフィールドに事前にデータを移入できます。例8-22のように、updateContactメソッドはContactオブジェクトをパラメータとして使用し、更新されたContactオブジェクトを戻します。

updateContactメソッドとContactオブジェクトの詳細は、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。Contactのプロパティについては、第8.5.5項「findContactsメソッドの使用方法」も参照してください。


注意:

入力パラメータとして必要なContactオブジェクトは、第8.5.5項「findContactsメソッドの使用方法」の説明に従ってfindContactsメソッドを使用することによって検索できます。nullのContactオブジェクトがメソッドに渡された場合、ADFの例外がスローされます。


DeviceFeaturesデータ・コントロールを使用してupdateContact操作をカスタマイズするには:

  1. JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからupdateContact操作をドラッグし、ADFモバイルのリンクまたはボタンとしてページ・デザイナ上にドロップします。

    リンクまたはボタン: 「アクション・バインディングの編集」ダイアログが表示され、updateContact操作に対するContactオブジェクトのパラメータを入力するよう求められます。このパラメータは、Java BeanクラスからContactを戻すために使用されるマネージドBeanのプロパティを参照するEL式である必要があります。マネージドBeanにContactオブジェクトのゲッターがすでに含まれている場合は、EL式ビルダーを使用して、パラメータの値を設定できます。実行時にページに表示されるボタンまたはリンクをクリックすると、入力した値を使用してupdateContact操作を実行できます。例8-16は、Contactオブジェクトを作成するためのマネージドBeanコードの例を示しています。

  2. 戻されたContactオブジェクトを「データ・コントロール」パネルにあるupdateContact操作の下からドラッグし、ADFフォームとしてページ上にドロップすることもできます。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。updateContact操作を実行すると、結果がこのフォームに表示されます。

例8-22例8-24は、コンタクト先の電話番号を更新する方法を示しています。例8-23例8-25は、コンタクト先に別の電話番号を追加する方法を示しています。

例8-22 updateContactのJavaScriptコード例

function updateContact(contact)
{
  try
  {
    if (null != contact.phoneNumbers)
    {
      alert("Number of phone numbers = " + contact.phoneNumbers.length);
      var numPhoneNumbers = contact.phoneNumbers.length;
      for (var j = 0; j < numPhoneNumbers; j++)
      {
        alert("Type: " + contact.phoneNumbers[j].type + "\n" +
              "Value: "  + contact.phoneNumbers[j].value + "\n" +
              "Preferred: "  + contact.phoneNumbers[j].pref);
 
        contact.phoneNumbers[j].type = "mobile";
        contact.phoneNumbers[j].value = "408-555-0100";
      }
 
      // save
      contact.save(onSuccess, onFailure);
    }
    else
    {
      //alert ("No phone numbers found in the contact.");
    }
  }
  catch(e)
  {
    alert("updateContact - ERROR: " + e.description);
  }
}
 
function onSuccess()
{
  alert("Update Contact successful.");
}
 
function onFailure(Error)
{
  alert("Update Contact failed: " + Error.code);

例8-23は、既存の電話番号に別の電話番号を追加する方法を示しています。

例8-23 updateContactを使用して電話番号を追加するためのJavaScriptコード例

function updateContact(contact)
{
  try
  {
    var phoneNumbers = [1];
    phoneNumbers[0] = new ContactField('home', '650-555-0123', true);
    contact.phoneNumbers = phoneNumbers;
 
    // save
    contact.save(onSuccess, onFailure);
  }
  catch(e)
  {
    alert("updateContact - ERROR: " + e.description);
  }
}
 
function onSuccess()
{
  alert("Update Contact successful.");
}
 
function onFailure(Error)
{
  alert("Update Contact failed: " + Error.code);
}

例8-24は、コンタクト先の電話番号、電子メール・タイプおよび郵便番号を更新する方法を示しています。

例8-24 updateContactのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

/*
 * Update Contact - Updating phone number, email type, and adding address postal code
 */
String familyName = "FamilyName";
String phoneNumberNewValue = "650-555-0123";
String emailTypeNew = "work";
String addressPostalCode = "91234";

Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts(
    "name,phoneNumbers,emails,addresses,note", familyName, true); 

// Assuming there was only one contact returned, we can use the first contact in the array.
// If more than one contact is returned then we have to filter more to find the exact contact 
// we need to update.

foundContacts[0].getPhoneNumbers()[0].setValue(phoneNumberNewValue);
foundContacts[0].getEmails()[0].setType(emailTypeNew);
foundContacts[0].getAddresses()[0].setPostalCode(addressPostalCode);

Contact updatedContact = DeviceManagerFactory.getDeviceManager().updateContact(foundContacts[0]);

例8-25は、既存の電話番号に別の電話番号を追加する方法を示しています。

例8-25 updateContactを使用して電話番号を追加するためのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

String additionalPhoneNumberValue = "408-555-0123";
String additionalPhoneNumberType = "mobile";
// Create a new phoneNumber that will be appended to the previous one.
ContactField additionalPhoneNumber = new ContactField();
additionalPhoneNumber.setType(additionalPhoneNumberType);
additionalPhoneNumber.setValue(additionalPhoneNumberValue);

foundContacts[0].setPhoneNumbers(new ContactField[] { additionalPhoneNumber });

// Access device features in Java code by acquiring an instance of the DeviceManager 
// from the DeviceManagerFactory.
Contact updatedContact = DeviceManagerFactory.getDeviceManager().updateContact(foundContacts[0]);

8.5.7 removeContactメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるremoveContactメソッドをADFモバイル・アプリケーションで使用すると、コンタクト先を管理するためのデバイスの・インタフェースとファイル・システムを活用し、エンド・ユーザーがデバイスのアドレス帳からコンタクト先を削除できるようにすることが可能です。ADFモバイルでは、デバイスのインタフェースを表示し、必要に応じてremoveContactのフィールドに事前にデータを移入できます。例8-26のように、removeContactメソッドはContactオブジェクトをパラメータとして使用します。


注意:

入力パラメータとして必要なContactオブジェクトは、第8.5.5項「findContactsメソッドの使用方法」の説明に従ってfindContactsメソッドを使用することによって検索できます。


DeviceFeaturesデータ・コントロールを使用してremoveContact操作をカスタマイズするには:

  1. JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからremoveContact操作をドラッグし、ADFモバイルのリンクボタンまたはパラメータ・フォームとしてページ・デザイナ上にドロップします。

    リンクまたはボタン: 「アクション・バインディングの編集」ダイアログが表示され、removeContact操作の引数の値を入力するよう求められます。実行時にページに表示されるボタンまたはリンクをクリックすると、入力した値を使用してremoveContact操作を実行できます。

    パラメータ・フォーム: 「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズします。実行時に、アプリケーション・ユーザーが様々なContactのフィールドの値を入力できる、編集可能なフォームがページに表示されます。このフォームの下にあるボタンをクリックすると、入力した値を使用してremoveContact操作を実行できます。

  2. 戻されたContactオブジェクトを「データ・コントロール」パネルにあるremoveContact操作の下からドラッグし、ADFフォームとしてページ上にドロップすることもできます。その後、「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズできます。removeContact操作を実行すると、結果がこのフォームに表示されます。

例8-26例8-27は、findContactsを使用して検索したコンタクト先を削除する方法を示しています。removeContactメソッドとContactオブジェクトの詳細は、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。


注意:

Androidでは、removeContact操作を実行しても完全にはコンタクト先が削除されません。removeContactメソッドをコールしてコンタクト先を削除すると、「(不明)」の付いた名前がアプリケーション内のコンタクト先リストに表示されます。


例8-26 removeContactのJavaScriptコード例

// Remove the contact from the device
contact.remove(onSuccess,onError);
 
function onSuccess()
{
  alert("Removal Success");
}
 
function onError(contactError)'
{
  alert("Error = " + contactError.code);
}

例8-27 removeContactのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

/*
 * Remove the contact from the device
 */
Contact[] foundContacts = DeviceManagerFactory.getDeviceManager().findContacts(
    "name,phoneNumbers,emails,addresses", familyName, true);

// Assuming there is only one contact returned, we can use the first contact in the array.
// If more than one contact is returned we will have to filter more to find the  
// exact contact we want to remove.

// Access device features in Java code by acquiring an instance of the DeviceManager 
// from the DeviceManagerFactory.
DeviceManagerFactory.getDeviceManager().removeContact(foundContacts[0]);

注意:

removeContactメソッドのタイムアウト値は、1分に設定されます。デバイス操作に、許可されたタイムアウトよりも長い時間がかかった場合は、タイムアウト・エラーが表示されます。


8.5.8 startLocationMonitorメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるstartLocationMonitorメソッドをADFモバイル・アプリケーションで使用すると、地理的位置機能を提供し、エンド・ユーザーがデバイスの場所を取得できるようにすることが可能です。ADFモバイルでは、デバイスのインタフェースを表示し、必要に応じてstartLocationMonitorのフィールドに事前にデータを移入できます。

ADFモバイルで公開されているAPIを使用すると、デバイスの現在の位置を取得できるため、特定の時点におけるデバイスの現在の位置を取得したり、定期的にその情報をサブスクライブできます。例8-28例8-29は、アプリケーションでデバイスの位置の取得を可能にするコード例を示しています。startLocationMonitorメソッドについては、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

DeviceFeaturesデータ・コントロールを使用してデバイスの位置の変更をリスニングするには:

JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからstartLocationMonitor操作をページ・デザイナ上にドラッグし、ADFモバイルのリンクまたはボタンとしてドロップします。アクションの編集ダイアログによって要求されたら、次のようにフィールドに値を移入します。

  • enableHighAccuracy: trueの場合、位置の修正を最も正確に取得できるメソッドを使用します。これは単なるヒントであり、オペレーティング・システムでは考慮されない場合があります。多くの場合、デバイスには、携帯電話基地局の三角測量、Wi-Fiホットスポットの参照、実際のGPSなど、位置の修正を取得するためのいくつかの異なるメカニズムがあります。falseを指定すると、正確性の低い位置を受け入れることになりますが、この場合、レスポンスの速度が向上し、消費電力が低下する可能性があります。

  • updateInterval: 更新の受信頻度をミリ秒単位で定義します。位置の更新は、指定した頻度では配信されない場合があります。オペレーティング・システムでは、デバイスの位置の大きな変更が検出されるまで待機してから、別の位置の更新をトリガーする場合があります。

  • locationListener: 次のシグネチャを含むBeanメソッドに解決されるEL式。

    void methodName(Location newLocation)
    

    このEL式は、位置の更新を受信するたびに評価されます。たとえば、viewScope.LocationListenerBean.locationUpdated(#{}で囲みません)と入力した後、LocationListenerBeanというBeanをviewScope内に定義し、次のシグネチャを含むメソッドを実装します。

    public void locationUpdated(Location currentLocation)
    {
      System.out.println(currentLocation);
      // To stop subscribing to location updates, invoke the following:
      // DeviceManagerFactory.getDeviceManager().clearWatchPosition(
      //     currentLocation.getWatchId());
    }
    

    注意:

    EL式の評価結果としてlocationListenerの名前が必要でないかぎり、locationListenerを指定するためにEL構文#{LocationListenerBean.locationUpdate}を使用しないでください。


例8-28は、デバイスの位置の変更を定期的にサブスクライブする方法を示しています。この例で使用するDeviceManager.startUpdatingPositionメソッドのパラメータは、次のとおりです。

  • int updateInterval: 位置の更新の配信頻度をミリ秒単位で定義します。位置の更新は、指定した頻度では配信されない場合があります。オペレーティング・システムでは、デバイスの位置の大きな変更が検出されるまで待機してから、別の位置の更新をトリガーする場合があります。逆に言えば、位置の更新は指定した頻度で配信されることもありますが、デバイスの位置が大きく変更されるまで、配信される位置が変化しない場合があります。

  • boolean enableHighAccuracy: trueに設定された場合、位置の修正を最も正確に取得できるメソッドを使用します。

  • String watchID: 後から位置の更新のサブスクライブを停止するために使用できる一意のIDを定義します。

  • GeolocationCallback: GeolocationCallbackインタフェースの実装。例8-28のように、この実装のlocationUpdatedメソッドは、位置が更新されるたびに起動されます。

JavaScriptを使用してデバイスの位置の変更をサブスクライブする方法の例は、Cordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

locationListenerによって指定されたコールバック関数内に戻されるパラメータは、次のとおりです。

  • double getAccuracy: m単位の緯度と経度を示す座標の精度レベル。

  • double getAltitude: m単位の楕円体高度。

  • double getLatitude: 10進度単位の緯度。

  • double getLongitude: 10進度単位の経度。

  • double getAltitudeAccuracy: m単位の高度座標の精度レベル。

  • double getHeading: 真北から時計回りに計測した度単位で示される進行方向

  • double getSpeed: m/秒単位で指定される、デバイスの現在の対地速度

  • long getTimestamp: Unixエポックからのミリ秒単位の経過時間で示されるタイムスタンプの作成

  • String getWatchId: 定期的な位置の更新をサブスクライブするときのみ使用します。後から位置の更新のサブスクライブを停止するために使用できる一意のID

startLocationMonitorおよびstartHeadingMonitorメソッドの詳細は、ADFモバイルJavadocのDeviceDataControlクラスおよびCordovaのドキュメント(http://docs.phonegap.com/en/2.2.0/index.html)を参照してください。

例8-28 地理的位置を使用したデバイスの位置の変更のサブスクライブ

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;
import oracle.adf.model.datacontrols.device.GeolocationCallback;
import oracle.adf.model.datacontrols.device.Location;

// Subscribe to location updates that will be delivered every 20 seconds, with high accuracy.
// As we can have multiple subscribers, let's identify this one as 'MyGPSSubscriptionID'.
// Notice that this call returns the watchID, which is usually the same as the watchID passed in.
// However, it may be different if the specified watchID conflicts with an existing watchID,
// so be sure to always use the returned watchID.
String watchID = DeviceManagerFactory.getDeviceManager().startUpdatingPosition(20000, true, "
       "MyGPSSubscriptionID", new GeolocationCallback() {
    public void locationUpdated(Location position) {
        System.out.println("Location updated to: " + position);
    }
});

// The previous call returns immediately so that you can continue processing. 
// When the device's location changes, the locationUpdated() method specified in  
// the previous call will be invoked in the context of the current feature.

// When you wish to stop being notified of location changes, call the following method:
DeviceManagerFactory().getDeviceManager().clearWatchPosition(watchID);

DeviceFeaturesデータ・コントロールを使用してデバイスの位置を取得するには:

JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからstartLocationMonitor操作をページ・デザイナ上にドラッグし、ADFモバイルのリンクまたはボタンとしてドロップします。例8-28に従いますが、最初の位置の変更を受信した後、リスニングを停止します。

例8-29は、デバイスの位置を1回取得する方法を示しています。この例で使用するDeviceManager.getCurrentPositionメソッドのパラメータは、次のとおりです。

  • int maximumAge: ミリ秒単位で指定したこの値より古くないキャッシュ値を受け入れます。位置の修正をこの時間内に取得した場合、その情報がすぐに戻されますが、それ以外の場合、コールは新しい位置の修正が確定するまでブロックされます。maximumAgeパラメータの値は、1000ミリ秒以上である必要があります。これより小さい値は、自動的に1000ミリ秒に設定されます。

  • boolean: enableHighAccuracy trueに設定された場合、位置の修正を最も正確に取得できるメソッドを使用します。

例8-29 地理的位置を使用したデバイスの現在位置の取得(1回)

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;
import oracle.adf.model.datacontrols.device.Location;

// Get the device's current position, with highest accuracy, and accept a cached location that is 
// no older than 60 seconds.
Location currentPosition = DeviceManagerFactory.getDeviceManager().getCurrentPosition(60000, true);
System.out.println("The device's current location is: latitude=" + currentPosition.getLatitude() + 
    ", longitude=" + currentPosition.getLongitude());

8.5.9 displayFileメソッドの使用方法

DeviceFeaturesデータ・コントロールに含まれるdisplayFileメソッドを使用すると、デバイスのローカル・ファイルを表示できます。プラットフォームに応じて、アプリケーション・ユーザーはPDF、イメージ・ファイル、Microsoft Officeドキュメントおよびその他の様々なファイル・タイプを表示できます。iOSでは、アプリケーション・ユーザーは、サポートされているファイルをADFモバイル・アプリケーション内でプレビューできます。またユーザーは、それらのファイルをサードパーティ・アプリケーションで開く、電子メールで送信する、プリンタに送信するなどの操作を行うこともできます。Androidでは、すべてのファイルがサードパーティ・アプリケーション内で開かれます。つまり、アプリケーション・ユーザーは、ファイルを表示しながらADFモバイル・アプリケーションから離れることができます。ユーザーは、Androidの戻るボタンを押すことによって、ADFモバイル・アプリケーションに戻ることができます。所定のファイルを開くことができるアプリケーションがデバイス内に存在しない場合は、エラーが表示されます。

displayFileメソッドの機能は、デバイスのローカル・ファイルを表示することのみです。つまり、リモート・ファイルは最初にダウンロードする必要があります。ダウンロードされたファイルの格納先であるディレクトリ・ルートに戻るには、AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory)をコールします。iOSでは、この場所はアプリケーションによって異なりますが、Androidでは、この場所として外部ストレージ・ディレクトリが参照されます。この外部ストレージ・ディレクトリは公的にアクセス可能であるため、サードパーティ・アプリケーションを使用して、そこに格納されているファイルを読み取ることができます。

表8-6 サポートされるファイル・タイプ

iOS Android

サポートされるファイル・タイプの詳細は、Apple iOS開発サイト(http://developer.apple.com/library/ios/navigation/)にある、Quick Lookプレビュー・コントローラに関するドキュメントを参照してください。

特定のMIMEタイプがデバイスにインストールされている場合、このフレームワークによって、そのタイプに関連付けられたビューアが起動されます。特定のファイル・タイプを表示するためのフレームワークは組み込まれていません。そのファイル・タイプを開くことができるアプリケーションがデバイスにインストールされていない場合は、ADFモバイル・アプリケーションによってエラーが表示されます。

iWorkドキュメント


Microsoft Officeドキュメント(Office 97以降)


リッチ・テキスト・フォーマット(RTF)ドキュメント


PDFファイル


イメージ


Uniform Type Identifier (UTI)がpublic.text typeに準拠しているテキスト・ファイル


カンマ区切り(csv)ファイル



DeviceFeaturesデータ・コントロールを使用してdisplayFile操作をカスタマイズするには:

  1. JDeveloperで、「データ・コントロール」パネルのDeviceFeaturesデータ・コントロールからdisplayFile操作をドラッグし、ADFモバイルのリンクボタンまたはパラメータ・フォームとしてページ・デザイナ上にドロップします。

    リンクまたはボタン: 「アクション・バインディングの編集」ダイアログが表示され、displayFile操作の引数の値を入力するよう求められます。実行時にページに表示されるボタンまたはリンクをクリックすると、入力した値を使用してdisplayFile操作を実行できます。

    パラメータ・フォーム: 「フォーム・フィールドの編集」ダイアログでフォームをカスタマイズします。実行時に、アプリケーション・ユーザーが様々なフィールドの値を入力できる、編集可能なフォームがページに表示されます。このフォームの下にあるボタンをクリックすると、入力した値を使用してdisplayFile操作を実行できます。

例8-30は、displayFileメソッドを使用してファイルを表示する方法を示しています。displayFileメソッドの詳細は、ADFモバイルJavadocのDeviceDataControlクラスを参照してください。

例8-30 displayFileのJavaコード例

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

 URL remoteFileUrl;
        InputStream is;
        BufferedOutputStream fos;
        try {
           
            // Open connection to remote file; fileUrl here is a String containing the URL to the remote file.
            remoteFileUrl = new URL(fileUrl);
            URLConnection connection = remoteFileUrl.openConnection();
            is = new BufferedInputStream(connection.getInputStream());
            // Saving the file locally as 'previewTempFile.<extension>'
            String fileExt = fileUrl.substring(fileUrl.lastIndexOf('.'), fileUrl.length());
            String tempFile = "/previewTempFile" + fileExt;
            File localFile = null;
            // Save the file in the DownloadDirectory location
            localFile = new File(AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.DownloadDirectory) + tempFile);
            if (localFile.exists()) {
                localFile.delete();
            }
            // Use buffered streams to download the file.
            fos = new BufferedOutputStream(new FileOutputStream(localFile));
            byte[] data = new byte[1024];
            int read = 0;
            while ((read = is.read(data)) != -1) {
                fos.write(data, 0, read);
            }
            is.close();
            fos.close();
 
            // displayFile takes a URL string which has to be encoded on iOS.
            // iOS does not handle "+" as an encoding for space (" ") but
            // expects "%20" instead.  Also, the leading slash MUST NOT be
            // encoded to "%2F".  We will revert it to a slash after the
            // URLEncoder converts it to "%2F".
            StringBuffer buffer = new StringBuffer();
            String path = URLEncoder.encode(localFile.getPath(), "UTF-8");
            // replace "+" with "%20"
            String replacedString = "+";
            String replacement = "%20";
            int index = 0, previousIndex = 0;
            index = path.indexOf(replacedString, index);
            while (index != -1) {
                buffer.append(path.substring(previousIndex, index)).append(replacement);
                previousIndex = index + 1;
                index = path.indexOf(replacedString, index + replacedString.length());
            }
            buffer.append(path.substring(previousIndex, path.length()));
            // Revert the leading encoded slash ("%2F") to a literal slash ("/").
            if (buffer.indexOf("%2F") == 0) {
                buffer.replace(0, 3, "/");
            }
 
            // Create URL and invoke displayFile with its String representation.
            URL localURL = null;
            if (Utility.getOSFamily() == Utility.OSFAMILY_ANDROID) {
                localURL = new URL("file", "localhost", localFile.getAbsolutePath());
            }
            else if (Utility.getOSFamily() == Utility.OSFAMILY_IOS)
            {
                localURL = new URL("file", "localhost", buffer.toString());
            }
            DeviceManagerFactory.getDeviceManager().displayFile(localURL.toString(), "remote file");
        } catch (Throwable t) {
            System.out.println("Exception caught: " + t.toString());
        }

8.5.10 デバイス・プロパティ

アプリケーションには、特定のデバイスの特性や機能に依存する機能が含まれる場合があります。たとえば、デバイスの画面の向きによって異なるユーザー・インタフェースを提示したり、デバイスで地理的位置がサポートされる場合のみマッピング機能を有効にすることなどが考えられます。ADFモバイルでは、このような動的な動作をサポートするためにJavaとELからアクセスできる、様々なプロパティが提供されます。表8-7に、これらのプロパティをリストし、問合せ方法、予期される戻り値およびアプリケーションのライフサイクル中にそのプロパティが変更される可能性があるかどうかに関する情報も提供します。

表8-7 デバイス・プロパティと対応するEL式

プロパティ 静的/
動的
EL式 サンプル値 Java API

device.name

静的

#{deviceScope.device.name}

"iPhone Simulator"、"Joe Smith's iPhone"

DeviceManager.getName()

device.platform

静的

#{deviceScope.device.platform}

"iPhone Simulator"、"iPhone"

DeviceManager.getPlatform()

device.version

静的

#{deviceScope.device.version}

"4.3.2"、"5.0.1"

DeviceManager.getVersion()

device.os

静的

#{deviceScope.device.os}

"iOS"

DeviceManager.getOs()

device.model

静的

#{deviceScope.device.model}

"x86_64"、"i386"、"iPhone3,1"

DeviceManager.getModel()

device.phonegap

静的

#{deviceScope.device.phonegap}

"1.0.0"

DeviceManager.getPhonegap()

hardware.hasCamera

静的

#{deviceScope.hardware.hasCamera}

"true"、"false"

DeviceManager.hasCamera()

hardware.hasContacts

静的

#{deviceScope.hardware.hasContacts}

"true"、"false"

DeviceManager.hasContacts()

hardware.hasTouchScreen

静的

#{deviceScope.hardware.hasTouchScreen}

"true"、"false"

DeviceManager.hasTouchScreen()

hardware.hasGeolocation

静的

#{deviceScope.hardware.hasGeolocation}

"true"、"false"

DeviceManager.hasGeolocation()

hardware.hasAccelerometer

静的

#{deviceScope.hardware.hasAccelerometer}

"true"、"false"

DeviceManager.hasAccelerometer()

hardware.hasCompass

静的

#{deviceScope.hardware.hasCompass}

"true"、"false"

DeviceManager.hasCompass()

hardware.hasFileAccess

静的

#{deviceScope.hardware.hasFileAccess}

"true"、"false"

DeviceManager.hasFileAccess()

hardware.hasLocalStorage

静的

#{deviceScope.hardware.hasLocalStorage}

"true"、"false"

DeviceManager.hasLocalStorage()

hardware.hasMediaPlayer

静的

#{deviceScope.hardware.hasMediaPlayer}

"true"、"false"

DeviceManager.hasMediaPlayer()

hardware.hasMediaRecorder

静的

#{deviceScope.hardware.hasMediaRecorder}

"true"、"false"

DeviceManager.hasMediaRecorder()

hardware.networkStatus

動的

#{deviceScope.hardware.networkStatus}

"wifi"、"2g"、"unknown"、"none"脚注 1 

DeviceManager.getNetworkStatus()

hardware.screen.width

動的

#{deviceScope.hardware.screen.width}

320、480

DeviceManager.getScreenWidth()

hardware.screen.height

動的

#{deviceScope.hardware.screen.height}

480、320

DeviceManager.getScreenHeight()

hardware.availableWidth

動的

#{deviceScope.hardware.screen.availableWidth}

<= 320、<= 480

DeviceManager.getAvailableScreenWidth()

hardware.availableHeight

動的

#{deviceScope.hardware.screen.availableHeight}

<= 480、<= 320

DeviceManager.getAvailableScreenHeight()

hardware.screen.dpi

静的

#{deviceScope.hardware.screen.dpi}

160、326

DeviceManager.getScreenDpi()

hardware.screen.diagonalSize

静的

#{deviceScope.hardware.screen.diagonalSize}

9.7、6.78

DeviceManager.getScreenDiagonalSize()

hardware.screen.scaleFactor

静的

#{deviceScope.hardware.screen.scaleFactor}

1.0、2.0

DeviceManager.getScreenScaleFactor()


脚注 1  wifi2Gの両方が有効になっている場合、wifi2Gよりも優先されるため、ネットワーク・ステータスはwifiになります。

8.6 検証の実行

ADFモバイルでは、データ・コントロール・レイヤーで検証を実行し、Oracle ADFの場合と同様に動作するバインディング属性に設定された検証ルールを使用します。属性の検証は、バインディングに対するsetValue操作中に、システム内の単一点で実行されます。

データ・コントロールによって公開される属性に対して、次のバリデータを定義できます。

特定の属性に対してすべてのバリデータが実行され、成功しないすべてのバリデータに対してネストされた例外がスローされます。属性の検証メッセージを定義し、実行時に検証ルールを起動するときに表示できます。詳細は、第7.9項「入力の検証」第8.6.1項「検証ルールの追加方法」を参照してください。


注意:

JSONの制限により、BigDecimalが保持できる値はDoubleの範囲内となり、BigIntegerが保持できる値はLongの範囲内となります。許可された値よりも大きい数値を使用するには、toStringBigDecimalまたはBigIntegerでコールし、値をStringとしてシリアライズ(解除)します。


表8-8に、長さバリデータでサポートされる検証の組合せをリストします。

表8-8 長さの検証

比較タイプ Byte Character

Equals

サポート

サポート

Not Equals

サポート

サポート

Less Than

サポート

サポート

Greater Than

サポート

サポート

Less Than Equal To

サポート

サポート

Greater Than Equal To

サポート

サポート

Between

サポート

サポート


表8-9表8-10に、範囲バリデータでサポートされる検証の組合せをリストします。

表8-9 範囲検証

比較タイプ Byte Char Double Float Integer Long Short

Between

サポート

サポート

サポート

サポート

サポート

サポート

サポート

Not Between

サポート

サポート

サポート

サポート

サポート

サポート

サポート


表8-10 範囲検証: math、sqlおよびutilパッケージ

比較タイプ java.math.BigDecimal java.math.BigInteger java.sql.Date java.sql.Time java.sql.Timestamp java.util.Date

Between

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Not Between

サポート

サポート

未サポート

未サポート

未サポート

未サポート


表8-11に、リスト・バリデータでサポートされる検証の組合せをリストします。

表8-11 リスト検証

比較タイプ String

In

サポート

Not In

サポート


表8-12表8-13に、比較バリデータでサポートされる検証の組合せをリストします。

表8-12 比較検証

比較タイプ Byte Char Double Float Integer Long Short String

Equals

サポート

サポート

サポート

サポート

サポート

サポート

サポート

サポート

Not Equals

サポート

サポート

サポート

サポート

サポート

サポート

サポート

サポート

Less Than

未サポート

サポート

サポート

サポート

サポート

サポート

サポート

未サポート

Greater Than

未サポート

サポート

サポート

サポート

サポート

サポート

サポート

未サポート

Less Than Equal To

未サポート

サポート

サポート

サポート

サポート

サポート

サポート

未サポート

Greater Than Equal To

未サポート

サポート

サポート

サポート

サポート

サポート

サポート

未サポート


表8-13 比較検証: java.math、java.sqlおよびjava.utilパッケージ

比較タイプ java.math.BigDecimal java.math.BigInteger java.sql.Date java.sql.Time java.sql.Timestamp java.util.Date

Equals

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Not Equals

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Less Than

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Greater Than

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Less Than Equal To

サポート

サポート

未サポート

未サポート

未サポート

未サポート

Greater Than Equal To

サポート

サポート

未サポート

未サポート

未サポート

未サポート


8.6.1 検証ルールの追加方法

検証ルールは、様々なユース・ケースに合わせて定義できます。宣言的検証ルールをエンティティ・オブジェクトに追加するには、データ・コントロール構造ファイルの「概要」エディタにある「属性」ページを使用します。

検証ルールの追加の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』のエンティティ・オブジェクトおよび属性への検証ルールの追加に関する項を参照してください。

検証規則を追加する手順:

  1. 「データ・コントロール」パネルで、データ・コントロール・オブジェクトを右クリックして「定義の編集」を選択します。

  2. データ・コントロール構造ファイルの「概要」エディタで、「属性」ページを選択します。

    「概要」エディタ: 「属性」ページ
  3. ページの下部にある「検証ルール」タブを選択し、「追加」をクリックします。表示された「検証ルールの追加」ダイアログで、検証ルールと失敗処理を定義します。

    「検証ルールの追加」ダイアログ

詳細は、次を参照してください:

8.6.2 バリデータのメタデータに関する必知事項

バリデータのメタデータは、設計時にデータ・コントロール構造のメタデータXMLファイル内に配置されます。例8-31は、サンプルの長さバリデータを示しています。

例8-31 メタデータ・ファイル内で宣言された長さバリデータ

<?xml version="1.0" encoding="windows-1252" ?>
<!DOCTYPE PDefViewObject SYSTEM "jbo_03_01.dtd">
<PDefViewObject
   xmlns="http://xmlns.oracle.com/bc4j"
   Name="Product"
   Version="12.1.1.61.36"
   xmlns:validation="http://xmlns.oracle.com/adfm/validation">
   <DesignTime>
      <Attr Name="_DCName" Value="DataControls.ProductListBean"/>
      <Attr Name="_SDName" Value="mobile.Product"/>
   </DesignTime>
   <PDefAttribute
      Name="name">
      <validation:LengthValidationBean
         Name="nameRule0"
         OnAttribute="name"
         CompareType="GREATERTHAN"
         DataType="BYTE"
         CompareLength="5"
         Inverse="false"/>
   </PDefAttribute>
</PDefViewObject>

8.7 データ変更イベント

JDeveloperでは、データ変更イベントを単純化するために、プロパティ変更リスナー・パターンを使用します。多くの場合、JDeveloperを使用して、Beanのプロパティ・アクセッサから通知をソースとして参照するために必要なコードを生成できます。これを行うには、「アクセッサの生成」ダイアログの「プロパティの変更時にリスナーに通知」チェック・ボックスを選択します(詳細は第8.2.4.2項「ADFマネージドBean」を参照)。PropertyChangeSupportオブジェクトが自動的に生成され、新たに生成されたsetterメソッドにfirePropertyChangeへのコールが含まれます。また、addPropertyChangeListenerおよびremovePropertyChangeListenerメソッドが追加されるため、プロパティ変更リスナーは、このオブジェクトを使用して自身を登録および登録解除できます。これを使用してフレームワークはクライアント・キャッシュにプッシュする変更を取得し、データが変更されたことをユーザー・インタフェース・レイヤーに通知します。


注意:

PropertyChangeSupportオブジェクトを手動でクラスに追加する場合は、addPropertyChangeListenerおよびremovePropertyChangeListenerメソッドも(これらの明示的なメソッド名を使用して)含める必要があります。


プロパティ変更のみでは、すべてのデータ変更通知は解決されません。たとえば、データ・コントロールによってラップされたBeanがあり、アイテムのコレクションの公開が必要な場合が考えられます。リストの個々のアイテムが変更されたときはプロパティ変更で十分ですが、カーディナリティが変更されたときは十分ではありません。この場合、コレクション全体のプロパティ変更を起動すると、パフォーマンスが低下する可能性があるため、かわりにコレクションのデルタのみを更新します。これを行うには、ProviderChangeSupportクラスを使用して、単純なプロパティ変更に必要なデータよりも多くのデータを公開する必要があります。


注意:

ProviderChangeSupportオブジェクトは、自動的には生成されません。このオブジェクトは、手動でaddProviderChangeListenerおよびremoveProviderChangeListenerメソッドとともに(これらの明示的なメソッド名を使用して)クラスに追加する必要があります。


プロバイダ変更は、データ・コントロールによってラップされたBeanで公開されている動的なコレクションを保持しているときのみ必要になるため、起動するプロバイダ変更イベントは、次のいくつかのタイプのみになります。

ProviderChangeSupportクラスは、コレクション要素に関連する通知を送信するために使用され、これによって、Java Beanデータ・コントロール内で変更が発生したときにコンポーネントを適切に更新できます。このクラスが従うパターンは、自動的に生成されるPropertyChangeSupportクラスと似ていますが、ProviderChangeSupportとともに使用されるイベント・オブジェクトでは、操作のタイプや変更された要素のキーと位置などの詳細情報を送信します。ProviderChangeSupportでは、コレクションに対する要素(プロバイダ)の追加や削除など、コレクションに対する構造的な変更を取得します。PropertyChangeSupportでは、コレクション内の個々のアイテムに対する変更を取得します。

例8-32は、ProviderChangeSupportを使用して、コレクションの要素に対する構造的な変更(子を追加または削除する場合など)に関する通知を送信する方法を示しています。ProviderChangeListenerインタフェースとProviderChangeEventクラスの詳細は、ADFモバイルJavadocを参照してください。

例8-32 ProviderChangeSupportのコード例

public class NotePad {
   private   static    List                  
                       s_notes               = null;
 
/* manually adding property change listener as well as provider change listener. */
   protected transient PropertyChangeSupport 
                       propertyChangeSupport = new PropertyChangeSupport(this);
   protected transient ProviderChangeSupport 
                       providerChangeSupport = new ProviderChangeSupport(this);
 
    public NotePad() {
        …
    }
 
    public  mobile.Note[] getNotes() {
        mobile.Note n[] = null;
 
        synchronized (this)
        {
            if(s_notes.size() > 0) {
                n = (mobile.Note[])
                    s_notes.toArray(new mobile.Note[s_notes.size()]);
            }
            else {
                n = new mobile.Note[0];
            }
        }
 
        return n;
    }
 
    public void addNote() {
        System.out.println("Adding a note ....");
        Note  n = new Note();
        int   s = 0;
        
        synchronized (this)
        {
            s_notes.add(n);
            s = s_notes.size();
        }
 
        System.out.println("firing the events");
        providerChangeSupport.fireProviderCreate("notes", n.getUid(), n);
    }
    
    public void removeNote() {
        System.out.println("Removng a note ....");
        if(s_notes.size() > 0) {
            int     end = -1;
            Note    n   = null;
 
            synchronized (this)
            {
                end   = s_notes.size() - 1;
                n     = (Note)s_notes.remove(end);
            }
            
            System.out.println("firing the events");
        providerChangeSupport.fireProviderDelete("notes", n.getUid());
        }
    }
    
    public void RefreshNotes() {
        System.out.println("Refreshing the notes ....");
 
        providerChangeSupport.fireProviderRefresh("notes");
    }
    
    public void addProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.addProviderChangeListener(l);
    }
 
    public void removeProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.removeProviderChangeListener(l);
    }
 
    protected String   status;    
    
    /* --- JDeveloper generated accessors --- */
 
    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }
 
    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }
 
    public void setStatus(String status) {
        String oldStatus = this.status;
        this.status = status;
        propertyChangeSupport.firePropertyChange("status", oldStatus, status);
    }
 
    public String getStatus() {
        return status;
    }
}

データ変更は、JVMレイヤーからのレスポンス・メッセージや戻り値とともに、クライアントに(キャッシュするために)戻されます。これにより、JDeveloperではユーザー・インタフェースに対してリフレッシュするイベントと更新の数を縮小し、可能なかぎりフレームワークの効率を上げることができます。

ただし、バックグラウンド・スレッドで実行時間の長い処理(Webサービスの相互作用、データベースの相互作用、コストのかかる計算など)に対処し、ユーザー・アクションに依存しないユーザー・インタフェースへの通知を行うことが必要になる場合もあります。AMXページのデータを更新して、値が変更されたデータ・フィールドの現在の値を反映させる場合、AdfmfJavaUtilities.flushDataChangeEventをコールして現在キューに入っているデータ変更をクライアントに強制することによって、AMXページ全体のリロードによるパフォーマンスの低下を回避できます。


注意:

flushDataChangeEventメソッドは、バックグラウンド・スレッドからのみ実行できます。


例8-33は、flushDataChangeEventメソッドを使用して保留中のデータ変更をクライアントに強制する方法を示しています。oracle.adfmf.framework.api.AdfmfJavaUtilities.flushDataChangeEventの詳細は、Oracle Fusion Middleware Oracle ADFモバイルJava APIリファレンスを参照してください。

例8-33 データ変更イベントの例

 
/* Note – Simple POJO used by the NotePad managed bean or data control wrapped bean */      
 
package mobile;
 
import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
 
 
/**
 * Simple note object
 * uid   - unique id - generated and not mutable
 * title - title for the note - mutable
 * note  - note comment - mutable
 */
public class Note {
    /* standard JDeveloper generated property change support */
    protected transient PropertyChangeSupport 
                       propertyChangeSupport = new PropertyChangeSupport(this);
 
 
    private static boolean s_backgroundFlushTestRunning = false;
 
 
    public Note() {
        this("" + (System.currentTimeMillis() % 10000));
    }
 
    public Note(String id) {
        this("UID-"+id, "Title-"+id, "");
    }
 
    public Note(String uid, String title, String note) {
        this.uid     = uid;
        this.title   = title;
        this.note    = note;
    }
 
 
    /* update the current note with the values passed in */
    public void updateNote(Note n) {
        if (this.getUid().compareTo(n.getUid()) == 0) {
            this.setTitle(n.getTitle());
            this.setNote(n.getNote());
        } else {
            throw new IllegalArgumentException("note");
        }
    }
 
 
    /* background thread to simulate some background process that make changes */
    public void startNodeBackgroundThread(ActionEvent actionEvent) {
        Thread backgroundThread   = new Thread() {
            public void run() {
                System.out.println("startBackgroundThread enter - " + 
                                                      s_backgroundFlushTestRunning);
                
                s_backgroundFlushTestRunning = true;
                for(int i = 0; i <= iterations; ++i) {
                    try
                    {
                        System.out.println("executing " + i + " of " + iterations + "
                                " iterations.");
                        
                        /* update a property value */                    
                        if(i == 0) {
                            setNote("thread starting");
                        }
                        else if( i == iterations) {
                            setNote("thread complete");
                            s_backgroundFlushTestRunning = false;                        
                        }
                        else {
                            setNote("executing " + i + " of " + iterations + " iterations.");
                        }
                        setVersion(getVersion() + 1);
                        setTitle("Thread Test v" + getVersion());
                        AdfmfJavaUtilities.flushDataChangeEvent();  /* key line */
                    }
                    catch(Throwable t)
                    {
                        System.err.println("Error in the background thread: " + t);
                    }
 
                    try {
                        Thread.sleep(delay);  /* sleep for 6 seconds */
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        };
        
        backgroundThread.start();
    }
    
    protected String uid;
    protected String title;
    protected String note;
    protected int    version;
 
    protected int    iterations =  10;
    protected int    delay      = 500;
    
    
    /* --- JDeveloper generated accessors --- */
 
    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }
 
    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }
 
    public String getUid() {
        return uid;
    }
 
    public void setTitle(String title) {
        String oldTitle = this.title;
        this.title = title;
        propertyChangeSupport.firePropertyChange("title", oldTitle, title);
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setNote(String note) {
        String oldNote = this.note;
        this.note = note;
        propertyChangeSupport.firePropertyChange("note", oldNote, note);
    }
 
    public String getNote() {
        return note;
    }
 
    public void setVersion(int version) {
        int oldVersion = this.version;
        this.version = version;
        propertyChangeSupport.firePropertyChange("version", oldVersion, version);
    }
 
    public int getVersion() {
        return version;
    }
 
    public void setIterations(int iterations) {
        int oldIterations = this.iterations;
        this.iterations = iterations;
        propertyChangeSupport.
                 firePropertyChange("iterations", oldIterations, iterations);
    }
 
    public int getIterations() {
        return iterations;
    }
 
    public void setDelay(int delay) {
        int oldDelay = this.delay;
        this.delay = delay;
        propertyChangeSupport.
                firePropertyChange("delay", oldDelay, delay);
    }
 
    public int getDelay() {
        return delay;
    }
}
         
 
 
  
/* NotePad – Can be used as a managed bean or wrapped as a data control */
           
package mobile;
 
import java.util.ArrayList;
import java.util.List;
 
import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;
 
 
public class NotePad {
    private static List     s_notes                      = null;
    private static boolean  s_backgroundFlushTestRunning = false;
    
    protected transient     PropertyChangeSupport 
        propertyChangeSupport = new PropertyChangeSupport(this);
 
    protected transient     ProviderChangeSupport 
        providerChangeSupport = new ProviderChangeSupport(this);
 
    public NotePad() {
        if (s_notes == null) {
            s_notes = new ArrayList();
            
            for(int i = 1000; i < 1003; ++i) {
                s_notes.add(new Note(""+i));
            }
        }
    }
 
    public  mobile.Note[] getNotes() {
        mobile.Note n[] = null;
 
        synchronized (this)
        {
            if(s_notes.size() > 0) {
                n = (mobile.Note[])s_notes.
                     toArray(new mobile.Note[s_notes.size()]);
            }
            else {
                n = new mobile.Note[0];
            }
        }
 
        return n;
    }
 
    public void addNote() {
        System.out.println("Adding a note ....");
        Note  n = new Note();
        int   s = 0;
        
        synchronized (this)
        {
            s_notes.add(n);
            s = s_notes.size();
        }
 
        System.out.println("firing the events");
        
        /* update the note count property on the screen */
        propertyChangeSupport.
             firePropertyChange("noteCount", s-1, s);
 
        /* update the notes collection model with the new note */
        providerChangeSupport.
             fireProviderCreate("notes", n.getUid(), n);
 
        /* to update the client side model layer */
        AdfmfJavaUtilities.flushDataChangeEvent();
    }
    
    public void removeNote() {
        System.out.println("Removing a note ....");
        if(s_notes.size() > 0) {
            int     end = -1;
            Note    n   = null;
 
            synchronized (this)
            {
                end   = s_notes.size() - 1;
                n     = (Note)s_notes.remove(end);
            }
            
            System.out.println("firing the events");
            
            /* update the client side model layer */
            providerChangeSupport.
                fireProviderDelete("notes", n.getUid());
 
           /* update the note count property on the screen */
           propertyChangeSupport.
                firePropertyChange("noteCount", -1, end);
        }
    }
    
    public void RefreshNotes() {
        System.out.println("Refreshing the notes ....");
 
        /* update the entire notes collection on the client */
        providerChangeSupport.fireProviderRefresh("notes");
    }
    
    public int getNoteCount() {
        int size = 0;
        
        synchronized (this)
        {
            size = s_notes.size();
        }
       return size;
    }
 
    public void 
    addProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.addProviderChangeListener(l);
    }
 
    public void
    removeProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.removeProviderChangeListener(l);
    }
 
    public void 
    startListBackgroundThread(ActionEvent actionEvent) {
        for(int i = 0; i < 10; ++i) {
            _startListBackgroundThread(actionEvent);
            try {
                Thread.currentThread().sleep(i * 1234);
            } catch (InterruptedException e) {
            }
        }
    }
    
    public void 
    _startListBackgroundThread(ActionEvent actionEvent) {
        Thread backgroundThread   = new Thread() {
            public void run() {
                s_backgroundFlushTestRunning = true;
                
                for(int i = 0; i <= iterations; ++i) {
                    System.out.println("executing " + i + 
                          " of " + iterations + " iterations.");
                    
                    try 
                    {
                        /* update a property value */                    
                        if(i == 0) {
                            setStatus("thread starting");
                            addNote();  // add a note
                        }
                        else if( i == iterations) {
                            setStatus("thread complete");
                            removeNote();  // remove a note
                            s_backgroundFlushTestRunning = false;                        
                        }
                        else {
                            setStatus("executing " + i + " of " + 
                                    iterations + " iterations.");
                            
                            synchronized (this)
                            {
                                if(s_notes.size() > 0) {
                                    Note n =(Note)s_notes.get(0);
                                
                                    n.setTitle("Updated-" + 
                                          n.getUid() + " v" + i);
                                }
                            }
                        }
                        AdfmfJavaUtilities.
                                 flushDataChangeEvent();
                    }
                    catch(Throwable t)
                    {
                        System.err.
                        println("Error in bg thread - " + t);
                    }
 
                    try {
                         Thread.sleep(delay);
                    } catch (InterruptedException ex) {
                        setStatus("inturrpted " + ex);
                        ex.printStackTrace();
                    }
                }
            }
        };
        
        backgroundThread.start();
    }
 
    
    protected int iterations = 100;
    protected int delay      = 750;
 
    protected String   status;    
    
    /* --- JDeveloper generated accessors --- */
 
    public void 
    addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }
 
    public void 
    removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }
 
    public void setStatus(String status) {
        String oldStatus = this.status;
        this.status = status;
        propertyChangeSupport.
                firePropertyChange("status", oldStatus, status);
    }
 
    public String getStatus() {
        return status;
    }
 
    public void setIterations(int iterations) {
        int oldIterations = this.iterations;
        this.iterations = iterations;
        propertyChangeSupport.
                firePropertyChange("iterations", 
                                   oldIterations, iterations);
    }
 
    public int getIterations() {
        return iterations;
    }
 
    public void setDelay(int delay) {
        int oldDelay = this.delay;
        this.delay = delay;
        propertyChangeSupport.
                firePropertyChange("delay", oldDelay, delay);
    }
 
    public int getDelay() {
        return delay;
    }
}
         

StockTrackerサンプル・アプリケーションでは、データ変更イベントでJavaを使用してデータ変更をユーザー・インタフェースに反映する方法の例を示します。このサンプル・アプリケーションは、開発用コンピュータのJDeveloperインストール・ディレクトリ内にある次の場所のPublicSamples.zipファイルに含まれています。

jdev_install/jdeveloper/jdev/extensions/oracle.adf.mobile/Samples

サンプル・アプリケーションの詳細は、付録F「サンプルのADFモバイル・アプリケーション」を参照してください。