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

前
 
次
 

28 より複雑なページの作成

この章では、ADFデータ・バインディングを使用して、Fusion Webアプリケーションのページに複雑な機能を追加する方法を説明します。フォームおよびコマンド・コンポーネントを作成するためのパラメータを取るメソッドの使用方法についても説明します。また、コンテキスト・イベントの作成およびADFモデル・レベルの検証の使用に関する情報を示します。

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


注意:

この章で説明する実装メソッドのいくつかは、ページレベルの設計のためのものです。タスク・フローを使用している場合は、同じ機能の多くを実行できます。詳細は、第14章「ADFタスク・フローの概説」を参照してください。


28.1 より複雑なページの概要

基本的なページを作成してナビゲーション機能を追加すると、ページ間でパラメータを渡したり、宣言アクションを上書きする機能を提供するなどの、より複雑な機能を追加できます。Oracle ADFには、このような複雑な機能を実際のコードをほとんど使用せずに追加できる機能が数多く用意されています。

この章で説明する機能のいくつかは、他のメソッドでも実行できます。たとえば、個別のページ・フローではなくタスク・フローを使用している場合、タスク・フローのパラメータ渡しメカニズムを使用する必要があります。あるいは、ADFビジネス・コンポーネントを使用している場合は、ADFモデル検証規則ではなく、データ・モデル・プロジェクトにあるエンティティ・オブジェクトの検証規則を使用する必要があります。ビジネス・コンポーネントの検証規則の詳細は、第7章「検証とビジネス・ルールの宣言的な定義」を参照してください。

28.2 メソッドを実行するためのコマンド・コンポーネントの作成

アプリケーションにカスタム・メソッドが含まれている場合、これらのメソッドは「データ・コントロール」パネルに表示されます。これらのメソッドは、コマンド・ボタンとしてドラッグ・アンド・ドロップできます。ユーザーがボタンをクリックすると、メソッドが実行されます。

カスタム・メソッドの作成の詳細は、9.7項「サービス・メソッドによるアプリケーション・モジュールのカスタマイズ」および9.9項「UIクライアントへのカスタム・サービス・メソッドの公開」を参照してください。


注意:

タスク・フローを使用している場合、タスク・フロー定義からメソッドを直接コールできます。詳細は、15.5項「メソッド・コール・アクティビティの使用」を参照してください。


たとえば、Fusion Order DemoアプリケーションのStoreFrontモジュールのアプリケーション・モジュールにはupdateItemInCart(Integer, Integer, Boolean)メソッドが含まれています。このメソッドは、ショッピング・カート内の項目を更新します。ユーザーがこのメソッドを実行できるようにするには、図28-1のように、「データ・コントロール」パネルからupdateItemInCart(Integer, Integer Boolean)メソッドをドラッグします。

図28-1 「データ・コントロール」パネルに表示されたメソッド

「データ・コントロール」パネルのメソッド

28.2.1 カスタム・メソッドにバインドされたコマンド・コンポーネントの作成方法

要求されるビジネス・ロジックを実行するために、多くのメソッドでは、そのパラメータ(1つ以上)に対する値を必要とします。つまり、メソッドにバインドされたボタンを作成する際に、パラメータの値の取得元を指定する必要があります。

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

ページに追加できるカスタム・メソッドを作成します。

たとえば、updateItemInCart(Integer, Integer, Boolean)メソッドを使用する場合、更新するアイテムを指定する必要があります。

メソッドにバインドされたボタンを追加するには:

  1. 「データ・コントロール」パネルから、メソッドをページにドラッグします。


    ヒント:

    表またはフォームに含まれるデータを使用するメソッドのボタンをドロップする場合は、その表またはフォームの中にボタンをドロップする必要があります。


  2. ポップアップ・メニューから「作成」>→「メソッド」>→「ADFボタン」を選択します。

    メソッドがパラメータを取る場合は、「アクション・バインディングの編集」ダイアログが開きます。「アクション・バインディングの編集」ダイアログで、各パラメータの値を入力するか、「パラメータ」「値」列で「EL式ビルダーの表示」メニュー選択をクリックし、EL式ビルダーを起動します。

28.2.2 メソッドを使用してコマンド・コンポーネントを作成した場合の処理

メソッドをコマンド・ボタンとしてドロップすると、JDeveloperによって次の処理が行われます。

  • メソッドのメソッド・アクション・バインディングが定義されます。

  • メソッドがパラメータを取得する場合は、パラメータ値を保持するNamedData要素が作成されます。

  • ADF Facesコマンド・コンポーネント用のコードがJSFページに挿入されます。

  • actionListenerを使用して、ボタンにメソッドをバインドします。

  • メソッド・コールからの戻り値を使用します。

28.2.2.1 メソッド・アクション・バインディングの定義

JDeveloperはメソッドにアクション・バインディングを追加します。アクション・バインディングはRequiresUpdateModelプロパティを使用して、アクションを実行する前にモデルを更新する必要があるかどうかを判別します。コマンド操作の場合、デフォルトではこのプロパティはtrueに設定されています。つまり、ビュー・レイヤーでのすべての変更は、操作を実行する前にモデルに移動する必要があります。

28.2.2.2 メソッドでのパラメータの使用方法

パラメータを取得するメソッドをJSFページにドロップすると、メソッド・アクション・バインディングが作成されます。このバインディングにより、ユーザーがコマンド・コンポーネントをクリックしたときにメソッドが実行されるようになります。メソッドが実行するパラメータを要求する場合は、JDeveloperによって、各パラメータのNamedData要素も作成されます。これらの要素は、メソッドのパラメータを表します。

たとえば、updateItemInCart(Integer, Integer, Boolean)メソッド・アクション・バインディングには、パラメータに対するNamedData要素が含まれます。この要素は、アクション・バインディングの作成時に指定した値にバインドされます。例28-1に、updateItemInCart(Integer, Integer, Boolean)メソッドをドロップし、Integerパラメータ(productId)と別のIntegerパラメータ(quantity)およびBooleanパラメータ(named isSet)を適切な変数にバインドしたときに作成されるメソッド・アクション・バインディングを示します。

例28-1 パラメータ・メソッドのメソッド・アクション・バインディング

<methodAction id="updateItemInCart"
                  InstanceName="StoreServiceAMDataControl.dataProvider"
                  DataControl="StoreServiceAMDataControl"
                  RequiresUpdateModel="true" Action="invokeMethod"
                  MethodName="updateItemInCart" IsViewObjectMethod="false">
      <NamedData NDName="productId" NDType="java.lang.Integer"/>
      <NamedData NDName="quantity" NDType="java.lang.Integer"/>
      <NamedData NDName="isSet" NDType="java.lang.Boolean"/>
</methodAction>

28.2.2.3 ADF Facesコンポーネント・コードをJSFページに追加

JDeveloperはADF Facesコンポーネント用のコードをJSFページに追加します。22.4.2.3項「EL式を使用したナビゲーション操作へのバインド」で説明されているとおり、このコードは、他のどのコマンド・ボタンのコードとも同じです。ただし、このボタンは、組込み操作に対するアクション・バインディングのexecuteメソッドではなく、ドロップされたメソッドに対するメソッド・アクション・バインディングのexecuteメソッドにバインドされます。

28.2.2.4 EL式を使用したメソッドへのバインド

操作を使用してコマンド・ボタンを作成するときと同様に、メソッドを使用してコマンド・ボタンを作成すると、actionListener属性を使用して、ボタンがメソッドに自動的にバインドされます。ボタンは、EL式を使用して、指定されたメソッドのアクション・バインディングのexecuteプロパティにバインドされます。このEL式により、アプリケーション・モジュールに対してバインディングのメソッドが起動します。コマンド・ボタンのactionListener属性の詳細は、22.4.4項「実行時に行われる処理: アクション・イベントおよびアクション・リスナーの動作方法」を参照してください。


ヒント:

アクション・バインディングのexecuteメソッドにボタンをバインドするかわりに、executeメソッドを上書きするバッキングBean内のメソッドにボタンをバインドできます。そうすることで、元のメソッドの実行前か実行後に、ロジックを追加できるようになります。詳細は、28.4項「宣言メソッドのオーバーライド」を参照してください。


ナビゲーション操作のように、ボタンのdisabledプロパティは、EL式を使用してボタンを表示するかどうかを決定します。例28-2に、コマンド・ボタンをupdateItemInCart(Integer, Integer, Boolean)メソッドにバインドするためのEL式を示します。

例28-2 コマンド・ボタンをメソッドにバインドするためのJSFコード

<af:commandButton actionListener="#{bindings.updateItemInCart.execute}"
                          text="updateItemInCart"
                          disabled="#{!bindings.updateItemInCart.enabled}"/>

ヒント:

コマンド・ボタン・コンポーネントをページにドロップすると、以前にドロップされた同種のコンポーネントの数に基づいて自動的にIDが付けられます。たとえば、commandButton1commandButton2のようになります。このIDをより説明的なものに変更する場合は、ページ内のすべてのEL式でこのIDへの参照を手動で更新する必要があります。


28.2.2.5 メソッド・コールからの戻り値の使用

メソッド・コールからの戻り値を使用することもできます。例28-3に、文字列値を戻すカスタム・メソッドを示します。

例28-3 値を戻すカスタム・メソッド

/**
 * Custom method.
*/
    public String getHelloString() {
        return ("Hello World");
    }

例28-4に、コマンド・ボタンおよびoutputTextコンポーネントのJSFページのコードを示します。

例28-4 カスタム・メソッドをコールするコマンド・ボタン

<af:commandButton actionListener="#{bindings.getHelloString.execute}"
        text="getHelloString"
        disabled="#{!bindings.getHelloString.enabled}"
        id="helloButtonId"/>
<af:outputText value="#{bindings.return.inputValue}"
        id="helloOutputId"/>

ユーザーがコマンド・ボタンをクリックすると、カスタム・メソッドがコールされます。このメソッドは、outputTextコンポーネントの値として表示される文字列「Hello World」を戻します。

28.2.3 実行時に行われる処理: コマンド・ボタンのメソッド・バインディング

ユーザーがボタンをクリックすると、メソッド・バインディングによって、関連付けられているメソッドが起動し、NamedData要素にバインドされている値がパラメータとして渡されます。たとえば、updateItemInCartItem(Integer, Integer, Boolean)メソッドにバインドされたボタンをユーザーがクリックすると、メソッドによって製品Idおよび数量の値が取得され、ショッピング・カートが更新されます。

28.3 コマンド・コンポーネントを使用したパラメータ値の設定

1つのページでのアクションに対して、アプリケーション機能を判別するためのパラメータを設定する必要が生じる場合があります。たとえば、あるページから別のページの結果表へ移動する検索コマンド・ボタンを作成できます。ただし、結果表が表示されるのはパラメータ値がfalseの場合のみです。

ページ間でこのパラメータを渡す場合やパラメータ値のチェックに使用するメソッドを含める場合には、マネージドBeanを使用できます。検索ページのレンダリング時にマネージドBeanがインスタンス化され、このBeanのメソッドによってこのパラメータがチェックされます。このパラメータがnullの場合(ページが初めてレンダリングされる場合)は、値がtrueに設定されます。

カスタム・メソッドの作成の詳細は、9.7項「サービス・メソッドによるアプリケーション・モジュールのカスタマイズ」および9.9項「UIクライアントへのカスタム・サービス・メソッドの公開」を参照してください。


注意:

タスク・フローを使用している場合、タスク・フローのパラメータ渡しメカニズムを使用できます。詳細は、第16章「タスク・フローのパラメータの使用」を参照してください。


typeプロパティがactionに設定されたsetPropertyListenerコンポーネント(この検索を実行したコマンド・ボタンにネストされている)を使用してこのフラグがfalseに設定されるため、検索の実行後に結果表が表示されるようになります。マネージドBeanの使用の詳細は、20.4項「Fusion WebアプリケーションでのマネージドBeanの使用」を参照してください。

28.3.1 コマンド・コンポーネント内でのsetPropertyListenerを使用したパラメータの設定方法

setPropertyListenerコンポーネントを使用して、その他のオブジェクトの値を設定できます。このコンポーネントは、コマンド・コンポーネントの子である必要があります。

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

ページにコマンド・コンポーネントを作成します。

setPropertyListenerコンポーネントを使用するには:

  1. コンポーネント・パレットの「操作」パネルからsetPropertyListenerコンポーネントをドラッグして、子としてコマンド・コンポーネントにドロップします。

    または、このコンポーネントを右クリックし、「ボタンの内部に挿入」→「ADF Faces」→setPropertyListenerを選択します。

  2. 「プロパティ・リスナーの設定の挿入」ダイアログの「選択元」フィールドにパラメータ値を入力します。

  3. 「先」フィールドにパラメータのターゲットを入力します。


    ヒント:

    作成されるページのページ定義ファイルに直接パラメータ値を設定するかわりに、マネージドBeanまたはスコープにパラメータ値を格納することを考慮してください。次のページに直接設定すると、それ以降、ナビゲーションを簡単に変更できなくなります。詳細は、20.4項「Fusion WebアプリケーションでのマネージドBeanの使用」を参照してください。また、バインディング・コンテナ内のデータは、コンテナが準備されたリクエスト中にのみ有効です。データを設定してから次のページがレンダリングされるまでの間に、データが変更される場合があります。


  4. 「タイプ」ドロップダウン・メニューから「アクション」を選択します。

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

28.3.2 パラメータの設定時に行われる処理

setPropertyListenerコンポーネントを使用すると、次のページに移動する前にコマンド・コンポーネントによって値が設定されます。渡す必要がある値のソースまたは実際の値をfrom属性に設定すると、コンポーネントからその値へのアクセスが可能になります。to属性をターゲットに設定すると、コマンド・コンポーネントによってターゲットに値が設定されるようになります。例28-5に、false値を取得し、その値をsearchResultsマネージドBeanのinitialSearchフラグの値として設定するコマンド・コンポーネントのJSFページのコードを示します。

例28-5 setPropertyListenerコンポーネントを使用するコマンド・ボタンのJSFページ・コード

<af:commandButton actionListener="#{bindings.Execute.execute}"
                 text=Search>
      <af:setPropertyListener from="#{false}"
                          to="#{searchResults.initialSearch}"/>
                          type="action"/>
</af:commandButton>

28.3.3 実行時に行われる処理: コマンド・コンポーネントに対するsetPropertyListener

ユーザーがコマンド・コンポーネントをクリックすると、移動する前に、setPropertyListenerコンポーネントによってパラメータ値が設定されます。例28-5では、setPropertyListenerfalse値を取得し、その値をsearchResultsマネージドBeanのinitialSearch属性の値として設定しています。これで、レンダリングするかどうかを決定するためにこの値を認識する必要があるコンポーネントは、EL式#{searchResults.initialSearch}を使用してアクセスできます。

28.4 宣言メソッドのオーバーライド

操作またはメソッドをコマンド・ボタンとしてドロップすると、操作またはメソッドのexecuteメソッドに、そのボタンが自動的にバインドされます。ただし、既存のロジックの前または後に、ロジックの追加が必要になる場合もあります。


注意:

タスク・フローを使用している場合、タスク・フローからカスタム・メソッドをコールできます。詳細は、第14章「ADFタスク・フローの概説」を参照してください。


Jdeveloperを使用すると、バインディング・コンテナにアクセスするマネージドBeanでメソッドおよびプロパティを新規作成することにより、宣言的操作にロジックを追加できます。デフォルトでは、この生成されたコードによって、操作またはメソッドが実行されます。その後、このコードの前か後にロジックを追加できます。元の操作またはメソッドのexecuteプロパティではなく、この新規メソッドにコマンド・コンポーネントが自動的にバインドされます。その後、ユーザーがボタンをクリックすると、新規メソッドが実行されます。

たとえば、Fusion Order Demoアプリケーションの注文ページのCommit操作には、追加処理が必要です。「コミット」ボタンは「発注」に名前が変更され、orderPageBeanマネージドBeanのsubmitOrdersメソッドにロジックが追加されます。

宣言メソッドを上書きするには、マネージドBeanにコマンド・コンポーネントがバインドされる新規メソッドを保持させる必要があります。ページにバッキングBeanが関連付けられている場合は、JDeveloperによって、バインディング・オブジェクトへのアクセスに必要なコードがバッキングBeanに追加されます。ページにバッキングBeanが関連付けられていない場合は、作成を促す指示が表示されます。

28.4.1 宣言メソッドのオーバーライド方法

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

マネージドBeanで宣言メソッドをオーバーライドするメソッドを作成します。操作はデフォルトで使用できます。


注意:

現在、コマンド・コンポーネントのAction属性の値としてEL式が設定されている場合は、JDeveloperによってEL式が上書きされないため、宣言メソッドを上書きできません。次の手順を行う前に、この値を削除する必要があります。


宣言メソッドを上書きのするには:

  1. 上書きする操作またはメソッドをJSFページ上にドラッグし、UIコマンド・コンポーネントとしてドロップします。

    コンポーネントが作成され、ActionListener属性を使用してADFモデル・レイヤーの関連するバインディング・オブジェクトにバインドされます。

    「データ・コントロール」パネルでメソッドを使用したコマンド・コンポーネントの作成の詳細は、28.2項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。

    操作によるコマンド・コンポーネントの作成の詳細は、22.4.2項「コマンド・ボタンの作成時の処理」を参照してください。

  2. JSFページでコンポーネントをダブルクリックします。

  3. 「バインド・アクション・プロパティ」ダイアログで、次のいずれかの方法で、バッキングBeanとコンポーネントのバインド先とするメソッドを指定します。

    • 自動バインディングがそのページで有効化されている場合は、図28-2のように、バッキングBeanはすでに自動選択されています。

      図28-2 自動バインディングが有効化されているページの「バインド・アクション・プロパティ」ダイアログ

      自動バインディングが有効化されているページの「バインド・アクション・プロパティ」ダイアログ
      • 新規メソッドを作成するには、「メソッド」フィールドにメソッドの名前を入力します。このフィールドには、最初にデフォルト名が表示されています。

        または

      • 既存のメソッドを使用するには、「メソッド」フィールドのドロップダウン・リストからメソッドを選択します。

      • 「ADFバインディング・コードの生成」を選択します。

    • そのページで自動バインディングが使用されていない場合は、図28-3のように、既存のバッキングBeanから選択するか、新規作成できます。

      図28-3 自動バインディングが無効化されているページの「バインド・アクション・プロパティ」ダイアログ

      「バインド・アクション・プロパティ」ダイアログ。
      • 「新規」をクリックして、新しいバッキングBeanを作成します。「マネージドBeanの作成」ダイアログで、Beanおよびクラスに名前を付け、Beanのスコープを設定します。

        または

      • 既存のバッキングBeanおよびメソッドをドロップダウン・リストから選択します。


    注意:

    コマンド・コンポーネントにActionListener属性の値が存在する場合は常に、ボタンのバインド先はバインディングのexecuteプロパティであるとみなされます。そのバインディングを削除した場合は、ADFバインディング・コードを生成することを選択できなくなります。その場合は、コマンド・コンポーネントをダブルクリックする前に、コードを手動で挿入するか、ActionListenerのダミー値を設定する必要があります。


  4. バッキングBeanおよびメソッドを識別したら、「バインド・アクション・プロパティ」ダイアログで「OK」をクリックします。

    ソース・エディタでマネージドBeanが自動的に開きます。例28-6は、Beanに挿入されたコードを示しています。この例では、コマンド・ボタンがCommit操作にバインドされています。

    例28-6 バインディング・オブジェクトへのアクセス用にバッキングBeanで生成されたコード

    public String submitOrder() {
            BindingContainer bindings = getBindings();
            OperationBinding operationBinding =
                  bindings.getOperationBinding("Commit");
            Object result = operationBinding.execute();
            if (!operationBinding.getErrors().isEmpty()) {
                return null;
            }
    }
    
  5. これで、例28-7に示すように、バインディング・オブジェクトにアクセスする前または後に、ロジックを追加できます。

    例28-7 上書き後のメソッドに追加されたコード

    public String submitOrder() {
            DCBindingContainer bindings =
                (DCBindingContainer)JSFUtils.resolveExpression("#{bindings}");
            OperationBinding operationBinding =
                bindings.getOperationBinding("Commit");
            JUCtrlAttrsBinding statusCode =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderStatusCode");
            statusCode.setAttribute("OrderStatusCode", "PENDING");
            JUCtrlAttrsBinding orderDate =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderDate");
            orderDate.setAttribute("OrderDate", new Date());
            JUCtrlAttrsBinding orderId =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderId");
            JSFUtils.storeOnSession("orderId", orderId.getAttribute("OrderId"));
            JUCtrlAttrsBinding invoiceTotal =
                (JUCtrlAttrsBinding)bindings.findNamedObject("InvoiceTotal");
            JUCtrlAttrsBinding orderTotal =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderTotal");
            orderTotal.setAttribute("OrderTotal",
                 invoiceTotal.getAttribute("InvoiceTotal"));
            Object result = operationBinding.execute();
            ShoppingCartBean shoppingCartBean =
                 (ShoppingCartBean)JSFUtils.resolveExpression("#{shoppingCartBean}");
            shoppingCartBean.removeAllItems();
            return "orderSummary";
    }
    

    例28-7のコードは、FODユーティリティ・メソッドJSFUtils.resolveExpressionを使用して、EL式を解決しています。このようなメソッドのコードは、例28-8にあるコードに似ています。

    例28-8 EL式を解決するためのユーティリティ・メソッド

    public static Object resolveExpression(String expression) {
            FacesContext facesContext = getFacesContext();
            Application app = facesContext.getApplication();
            ExpressionFactory elFactory = app.getExpressionFactory();
            ELContext elContext = facesContext.getELContext();
            ValueExpression valueExp =
                elFactory.createValueExpression(elContext, expression, Object.class);
            return valueExp.getValue(elContext);
        }
    

    処理ロジックに加えて条件付きロジックを記述し、複数の結果の中から1つを戻すこともできます。たとえば、処理中にエラーが発生した場合にはnullを、処理が正常終了した場合は別の結果値を戻すことができます。nullの戻り値により、ナビゲーション・ハンドラはナビゲーション・ケースを評価せずに、そのまま現在ページを再表示します。


    ヒント:

    特定のナビゲーション・ケースをトリガーするには、メソッドによって戻される結果値が、ナビゲーション・ルールの結果値と(大/小文字も含めて)完全に一致する必要があります。


    この時点で、コマンド・ボタンは、ActionListener属性ではなく、Action属性を使用して新しいメソッドにバインドされています。Action属性の値(結果文字列など)がすでに存在していた場合は、その値が新規メソッドの戻りとして追加されます。値が存在していなかった場合は、戻りがnullのままになります。

28.4.2 宣言メソッドをオーバーライドした場合の処理

宣言メソッドをオーバーライドすると、JDeveloperにより、管理プロパティがバッキングBeanに追加され、この管理プロパティに値#{bindings}(バインディング・コンテナへの参照)が設定されます。また、強く型付けされたBeanプロパティがBindingContainer型のクラスに追加され、JSFランタイムにより、値として管理プロパティ式#{bindings}が設定されます。また、JDeveloperはUIコマンド・アクション・メソッドにロジックを追加します。このロジックには、現在のバインディング・コンテナへのアクセスに使用されている、強く型付けされたgetBindings()メソッドが含まれます。

このコードによって行われる処理は次のとおりです。

  • バインディング・コンテナにアクセスします。

  • 関連付けられているメソッドのバインディングを検索し、実行します。

  • ナビゲーションに使用できるメソッドの戻り値を追加します。デフォルトでは、戻り値はnullです。ボタンのAction属性に結果文字列がすでに存在する場合は、その属性が戻り値として使用されます。このコードは、必要に応じて変更できます。

ActionListener属性ではなく、Action属性を使用して新しいメソッドにUIコマンド・コンポーネントがリバインドされます。例28-9に、Commit操作が宣言的にページに追加される場合のコードを示します。

例28-9 宣言メソッドにバインドされたコマンド・ボタンのJSFページ・コード

<af:commandButton actionListener="#{bindings.Commit.execute}"
                  text="Commit" 
                  disabled="#{!bindings.Commit.enabled}"/>

例28-10に、ページのバッキングBeanのメソッドを上書きした後のコードを示します。ここでは、action属性は、バッキングBeanのメソッドにバインドされています。

例28-10 上書き後のメソッドにバインドされたコマンド・ボタンのJSFページ・コード

<af:commandButton text="#{res['order.cart.submit']}"
           action="#{orderPageBean.submitOrder}"/>

ヒント:

上書き後のメソッドを使用するボタンをクリックすると、次のエラーが表示されます。

SEVERE: マネージドBean main_beanを作成できませんでした。参照されるオブジェクトのスコープ: '#{bindings}'が、参照するオブジェクトより小さいです。

これは、上書き後のメソッドを含むマネージドBeanのスコープが、requestより大きい(つまり、sessionまたはapplicationである)ためです。メソッドで参照されるバインディング・コンテナ内のデータのスコープがrequestであるため、このマネージドBeanのスコープは同じか、より小さいスコープに設定する必要があります。


28.5 ADF Faces Calendarコンポーネントの使用方法

ADF Facesには、作成されたアクティビティを日、週、月単位のビューに表示するカレンダ・コンポーネントが含まれています。図28-4に、いくつかのサンプル・アクティビティがある週表示モードのADF Faces Calendarを示します。

図28-4 ADF Faces Calendar

ADF Faces Calendarコンポーネント

このコンポーネントには、次の機能も含まれています。

さらに、その他のADF Facesコンポーネントやリッチ・クライアント・フレームワークを使用して、次の機能を実装することもできます。

組込み機能の構成や、追加機能の実装に関する詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』の「カレンダ・アプリケーションの作成」の章に説明されています。

ADF Faces CalendarコンポーネントはCalendarModelクラスにバインドする必要があります。このクラスは、ユーザーがADFビジネス・コンポーネントを使用して、カレンダ・データを管理するときに、このユーザーのために作成することができます。たとえば、日付、時刻、件名、場所、所有者など、アクティビティの詳細を表すデータがデータ・ストアに入っているとします。このデータを表すエンティティ・オブジェクトを作成してから、このデータを表示するためのビュー・オブジェクトを作成した場合、関連するコレクションを「データ・コントロール」パネルからドラッグ・アンド・ドロップして、カレンダを作成できます。JDeveloperはモデルを宣言的に作成して、このモデルにビューをバインドし、カレンダを起動したときに正しいデータが表示されるようにします。ただし、モデルを作成するためには、ADFビジネス・コンポーネントを持つデータ・モデル・プロジェクトのエンティティ・オブジェクトおよび同じプロジェクト内のビュー・オブジェクトに、有効日指定の属性が必要です。また、ビュー・オブジェクトには、指定された日付範囲に対する正しいアクティビティを返すように問合せを修正するための変数も必要です。

28.5.1 ADF Faces Calendarの使用方法

JSFページでカレンダを作成する前に、まず、カレンダの属性を表す具体的な属性を持つエンティティ・オブジェクトを作成する必要があります。その後、このエンティティ・オブジェクトからビュー・オブジェクトを作成し、表示する日付範囲と現在のタイムゾーンを表す名前付きバインド変数を使用して、問合せを編集してください。これにより、この問合せから、カレンダの指定されたビューに表示すべきアクティビティのみが返されるようになります。

たとえば、あるアクティビティを表すデータベース表があるとします。これには、タイトル列、開始時刻、終了時刻、所有者を表すプロバイダ・オブジェクトへの参照が含まれています。この表に基づいて、(次の手順で説明するとおり、要件を満たすことを保証しながら)エンティティ・オブジェクトとビュー・オブジェクトを作成します。その後、ビュー・オブジェクトに、カレンダに現在表示されている開始時刻と終了時刻を表す名前付きバインド変数、カレンダで現在使用されているタイムゾーンを追加します。これにより、問合せはその時間範囲内に収まるアクティビティのみを返すようになります。

JSFページにカレンダ・コンポーネントを追加すると、これを構成して、必要な機能をさらに追加できるようになります。

ADF Faces Calendarを作成するには:

  1. データ・ソースに基づいて、エンティティ・オブジェクトを作成します。このエンティティ・オブジェクトには、表28-1に示す属性が含まれていなければなりません。これらの属性は、必ずしも、この表に示す名前を使用する必要はありません。どのような名前でもつけられます。ただし、記載されているタイプのいずれかでなければなりません。後述の手順で、これらの属性を、CalendarModelの属性にマップします。

    表28-1 カレンダに必須の属性

    属性 有効なタイプ 説明

    開始時刻

    java.util.Date、java.sql.Date、oracle.jbo.domain.Date、oracle.jbo.domain.TimeStamp

    アクティビティの開始時刻

    終了時刻

    java.util.Date、java.sql.Date、oracle.jbo.domain.Date、oracle.jbo.domain.TimeStamp

    アクティビティの開始時刻

    ID

    String

    一意のID

    プロバイダID

    String

    アクティビティの所有者を表すプロバイダ・オブジェクトのID

    タイトル

    String

    アクティビティの簡単な説明


    このエンティティ・オブジェクトも、表28-2に示す既知の属性を含むことができます(必須ではありません)。

    表28-2 カレンダに必要に応じて指定できる属性

    属性 タイプ 説明

    繰返し

    StringまたはCalendarActivity.Recurring

    アクティビティの繰返しステータス。有効な値はSINGLE(繰り返さない)、RECURRING(繰り返す)、またはCHANGED(このアクティビティは繰返しアクティビティの一部だが、修正されていて、親アクティビティとは異なる)です。

    アラーム

    StringまたはCalendarActivity.Reminder

    アクティビティに関連付けられたアラームがあるかどうか。有効な値はONまたはOFFです。

    時間タイプ

    StringまたはCalendarActivity.TimeType

    アクティビティに関連付けられている時間のタイプ。有効値はALLDAYおよびTIMEです。値ALLDAYを持つアクティビティには、時間は関連付けられていません。これらは1日中続くとみなされます。値TIMEを持つアクティビティは具体的な継続時間を持ちます。

    場所

    String

    アクティビティの場所。

    タグ

    StringsSet、またはセミコロンで区切られたStringsのリスト。

    アクティビティのキーワード


    エンティティ・オブジェクトは、CalendarModelが認識していない属性を含むこともできます。これらの属性は、後述の手順でカスタム・プロパティとしてモデルに追加できます。

    エンティティ・オブジェクトの作成の詳細は、第4章「エンティティ・オブジェクトを使用したビジネス・ドメイン・レイヤーの作成」を参照してください。

  2. 関連するビュー・オブジェクトを作成します。概要エディタの「問合せ」ページで、次に対する名前付きバインド変数を作成します。

    • タイムゾーンを表す文字列

    • カレンダに表示されている現在の日付範囲の開始日を表す日付

    • カレンダに表示されている現在の日付範囲の終了日を表す日付


      ヒント:

      ADF Facesカレンダの日付は「半分空いている」状態です。つまり、カレンダは、開始時刻ちょうど、またはそれ以降に始まり、終了時刻前に(ちょうどではない)アクティビティすべてを戻します。


      名前付きバインド変数の作成の詳細は、5.10項「バインド変数の使用」を参照してください。

  3. アクティビティのプロバイダ(所有者)を表すエンティティ・オブジェクトを作成します。このエンティティ・オブジェクトには、表28-3に示す属性が含まれていなければなりません。これらの属性は、必ずしも、この表に示す名前を使用する必要はありません。どのような名前でもつけられます。ただし、記載されているタイプでなければなりません。後述の手順で、これらの属性を、CalendarProviderの属性にマップします。

    表28-3 CalendarProviderクラスの属性

    属性 タイプ 説明

    ID

    String

    一意のID。

    表示名

    String

    カレンダに表示できるプロバイダ名。


  4. このプロバイダのビュー・オブジェクトを作成します。

  5. 新しいビュー・オブジェクトがアプリケーション・モジュールの一部であることを確認し、必要に応じて、「データ・コントロール」パネルをリフレッシュします。

  6. 20.3項「Webページの作成」の手順に従って、JSFページを作成します。

  7. 「データ・コントロール」パネルから、ステップ2で作成したアクティビティに対応するビュー・オブジェクトを表すコレクションをドラッグし、カレンダとしてドロップします。


    ヒント:

    「カレンダ」オプションは、ビュー・オブジェクトに表28-1に記載されている必須属性とステップ2で説明されているバインド変数が含まれている場合のみ、コンテキスト・メニューに表示されます。


  8. 「カレンダ・バインディング」ダイアログで、CalendarModelおよびCalendarProviderクラスにバインド変数と属性をマップします。詳細は、「ヘルプ」をクリックするか、[F1]を押してください。

  9. デフォルトでは、カレンダは読取り専用で、そのときにデータ・ストアに入っているアクティビティのみが返されます。『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』の「カレンダ・アプリケーションの作成」の章に説明されている手順に従って、カレンダを構成し、その他の機能を実装する必要があります。

    たとえば、新しいアクティビティを作成できるようにするには、カレンダの作成に使用したものと同じデータ・コントロールを使用し、(『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のダイアログの作成方法に関する項の説明に従って)ダイアログで入力フォームを作成します。入力フォームの作成に関する詳細は、22.6項「入力フォームの作成」を参照してください。

28.5.2 カレンダの作成時に行われる処理

コレクションをカレンダとしてドロップすると、JDeveloperにより次の処理が行われます。

  • アクティビティ・コレクションへのイテレータ・バインディングを1つと、プロバイダ・コレクションへのイテレータ・バインディングを1つ定義します。

  • アクティビティ・コレクションでexecuteWithParams操作へのアクション・バインディングを定義します。表示するアクティビティを返す問合せの実行のために呼び出されるのはこの操作です。この操作には日付範囲とタイムゾーンを決定するためのパラメータが必要であるため、(ビュー・オブジェクトで名前付きバインド変数として作成された)パラメータそれぞれについて、NamedData要素も作成されます。NamedData要素の詳細は、28.2.2.2項「メソッドでのパラメータの使用方法」を参照してください。

  • カレンダ・バインディングを定義します。このバインディングは、ウィザードで定義したとおり、コレクションの行を表すnode要素を含み、データ・コントロール属性をカレンダ・アクティビティの属性にマップします。valueはデータ・コントロール属性、typeはカレンダ属性です。カスタム定義属性では、typecustomvalueはデータ・コントロール属性になります。各行(ノード)はrowKeyで表されます。これはアクティビティIDです。

    また、利用可能なプロバイダのソースとマッピングを決定するproviderDefinition要素もあります。このマッピングにより、カレンダ・モデルはプロバイダの状態(有効または無効)に基づいてアクティビティをフィルタできるようになります。


    ヒント:

    カスタム属性にアクセスするには、value要素で定義された属性名で渡されるCalendarActivity.getCustomAttributes()メソッドを使用します。


    例28-11に、カレンダのページ定義コードを示します。

例28-11 カレンダ・バインディングのページ定義コード

<executables>
    <iterator Binds="ActivityView1" RangeSize="-1"
              DataControl="AppModuleDataControl" id="ActivityView1Iterator"/>
    <iterator Binds="EmployeesView1" RangeSize="25"
              DataControl="AppModuleDataControl" id="EmployeesView1Iterator"/>
  </executables>
  <bindings>
    <action IterBinding="ActivityView1Iterator" id="ExecuteWithParams"
            RequiresUpdateModel="true" Action="executeWithParams">
      <NamedData NDName="startTime"
                 NDValue="#{bindings.ActivityView1.startDate}"
                 NDType="oracle.jbo.domain.Date"/>
      <NamedData NDName="endTime" NDValue="#{bindings.ActivityView1.endDate}"
                 NDType="oracle.jbo.domain.Date"/>
      <NamedData NDName="timeZone"
                 NDValue="#{bindings.ActivityView1.timeZoneId}"
                 NDType="java.lang.String"/>
    </action>
    <calendar IterBinding="ActivityView1Iterator" id="ActivityView1"
              xmlns="http://xmlns.oracle.com/adf/faces/binding"
              ActionBindingName="ExecuteWithParams">
      <nodeDefinition DefName="model.ActivityView">
        <AttrNames>
          <Item Type="id" Value="Id"/>
          <Item Type="providerId" Value="ProviderId"/>
          <Item Type="title" Value="Title"/>
          <Item Type="startTime" Value="StartTime"/>
          <Item Type="endTime" Value="EndTime"/>
        </AttrNames>
      </nodeDefinition>
      <providerDefinition IterBindingName="EmployeesView1Iterator">
        <AttrNames>
          <Item Type="id" Value="EmployeeId"/>
          <Item Type="displayName" Value="FirstName"/>
        </AttrNames>
      </providerDefinition>
    </calendar>
  </bindings>

例28-12に示すとおり、JDeveloperはCalendarModelクラスにカレンダ値をバインドするコードをJSFページに挿入します。

例28-12 カレンダのJSFページ・コード

<af:form>
  <af:calendar value="#{bindings.ActivityView1.calendarModel}"/>
</af:form>

CalendarModelクラスは、カレンダ・バインディングへのアクセスにCalendarActivityDefinitionクラスを使用します。

28.5.3 実行時に行われる処理: カレンダ・バインディングの動作方法

カレンダにアクセスすると、executeWithParams操作が、カレンダ・コンポーネントのviewおよびactiveDay属性により決定されるstartDateおよびendDateパラメータ値を使って呼び出されます。たとえば、view属性がmonthactiveDayが当日の日付(ここでは、2009年2月6日とします)に設定されている場合、startDateの値はFebruary 1, 2009endDateの値はFebruary 28, 2009になります。デフォルトでは、タイムゾーン値はtrinidad-config.xmlファイルのtime-zone設定から取得されます(詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のtrinidad-config.xmlでの構成に関する項を参照してください)。したがって、問合せは、この日付範囲内に収まるアクティビティのみを返すように制限されます。

カレンダ・コンポーネントはCalendarModelにバインドされているため、問合せがデータを返すとき、CalendarModelCalendarActivityDefinitionクラスを使用して、カレンダ・バインディング・クラスにアクセスし、このバインディングが提供するマッピングを使用して、データ・ソースからカレンダに値をマップします。

28.6 ADF Faces Carouselコンポーネントの使用方法

図28-6に示すように、イメージを回転カルーセルに表示できます。正面にある画像を変更するには、下部のスライダを使用するか、または別の画像を正面にドラッグします。

図28-6 Carouselコンポーネント

Carouselコンポーネント

表示されるイメージごとに子carouselItemコンポーネントを組み込み、これらのコンポーネントを個々のイメージにバインドするかわりに、carouselコンポーネントを完成コレクションにバインドし、ツリーがデータの各行をスタンプ処理するのと同じ方法で、各アイテムの値をスタンプ処理して、1つのcarouselItemコンポーネントを繰り返しレンダリングします。各項目にスタンプが設定されると、現在の項目のデータが、carouselコンポーネントvar属性を使用するEL式を使用して特定可能なプロパティにコピーされます。カルーセルのレンダリングが完了したら、このプロパティは削除されるか前の値に戻ります。カルーセルはnodeStampファセットを持っています。このファセットは、各アイテムに関するテキストと簡単な説明の表示に使用されるcarouselItemコンポーネントのホルダーで、各アイテムについて表示されるイメージの親コンポーネントでもあります。Carouselコンポーネントの詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のカルーセルでの画像の表示に関する項を参照してください。

28.6.1 データバインドされたCarouselコンポーネントの作成方法

Fusion WebアプリケーションでCarouselコンポーネントを使用する場合、「データ・コントロール」パネルを使用して、コンポーネントを作成します。また、カルーセルのスピン・イベントの処理にはマネージドBeanを使用します。その他のロジックについては、アイテムの表示が必要になる可能性があります。

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

カルーセルに表示されるコレクションに対するビュー・オブジェクトを作成します。このビュー・オブジェクトには少なくとも次のアイテムに対する属性を組み込む必要があります。

  • タイトル。これは、カルーセル内の画像の下に表示されます。

  • 簡単な説明。これは、ユーザーが画像にマウスを重ねたときに表示されるテキストに使用されます。

データバインドされたCarouselコンポーネントを作成するには:

  1. 「データ・コントロール」パネルから、ビュー・オブジェクトで使用されるコレクションをページにドラッグし、ポップアップ・メニューから「カルーセル」を選択します。

  2. プロパティ・インスペクタの「動作」セクションで、ロジックを実行し、カルーセルを回転させる必要のあるときに、この回転を処理するハンドラ・メソッドにCarouselSpinListenerをバインドします。例28-13は、カルーセルの作成に使用されたProductsビュー・オブジェクトで製品画像の表示処理に使用されるハンドラ・メソッドを示します。

    例28-13 CarouselSpinEventのハンドラ

    public void handleCarouselSpin(CarouselSpinEvent event)
    {
      RichCarousel carousel = getCarousel();
      carousel.setRowKey(event.getNewItemKey());
      detailNodeItem = (JUCtrlHierNodeBinding)carousel.getRowData();
    }
    public JUCtrlHierNodeBinding getDetailNodeItem()
    {
    //   Get the initial item
      if(detailNodeItem == null)
      {
        RichCarousel carousel = getCarousel();
        
        Object oldKey = carousel.getRowKey();
        try
          {
             Object key = carousel.getCurrentItemKey();
              getCarousel().setRowKey(key);
              detailNodeItem = (JUCtrlHierNodeBinding)carousel.getRowData();
           }
        finally
         {
           carousel.setRowKey(oldKey);
          }
        }
         
      return detailNodeItem;
    }
       
    
  3. プロパティ・インスペクタの「拡張」セクションで、バインディング属性のドロップダウン・メニューをクリックし、「編集」を選択します。「属性の編集:バインディング」ダイアログで、ステップ2で作成したマネージドBeanを選択します。新しいプロパティcarouselを作成します。これにより、ハンドラ・メソッドがCarouselオブジェクトにアクセスできるようになります。

  4. 構造ウィンドウで、carouselコンポーネントとnodeStampファセットを展開し、carouselItemコンポーネントを選択します。

  5. CarouselItemコンポーネントのtext属性を、カルーセルのvar属性で設定されている変数値(デフォルトではitem)を使用して、データ・モデルの関連するプロパティにバインドします。したがって、carouselItemtext属性の値はitem.titleになります(titleがデータ・モデルのカルーセル・アイテムで使用されるテキストへのアクセスに使用されるプロパティである場合)。

    Productsビュー・オブジェクトを使用していた場合、この値は#{item.ProductName}になります。

  6. プロパティ・インスペクタの「拡張」セクションで、バインディング属性のドロップダウン・メニューをクリックし、「編集」を選択します。「属性の編集:バインディング」ダイアログで、ステップ2で作成したマネージドBeanを選択します。新しいプロパティcarouselItemを作成します。

  7. コンポーネント・パレットの「ADF Faces」ページで、「共通コンポーネント」パネルから、Imageをドラッグし、carouselItemの子としてドロップします。

    「イメージの挿入」ダイアログに、画像ソースへのパスを入力します。必ず、カルーセルでこのアイテムを表している変数を使用してください。たとえば、この製品の画像ファイルへのパスは通常、次のようになります。

    /imageservlet?detail=#{Products.ProductId}
    

    カルーセル内の画像については、次を使用します。

    /imageservlet?detail=#{item.ProductId}
    

    carouselおよびcarouselItemコンポーネントのその他の属性の設定に関する詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のカルーセルの作成方法に関する項を参照してください。

  8. カルーセル内のアイテムに関する追加情報を提供する場合は、同じビュー・オブジェクトをドラッグし、たとえばフォームとしてページにドロップすることができます。カルーセルが回転したら、そのときに表示されているアイテムの情報が再表示させるようにするには、フォーム内のコンポーネントで、このフォームが含まれるコンポーネントのpartialTrigger属性にCarouselコンポーネントのIDを設定する必要があります。

    たとえば、図28-6にある各アイテムの情報を表示するフォームはpanelBoxコンポーネントに含まれています。panelBoxコンポーネントのpartialTrigger属性はc1に設定されていますが、これはこのCarouselコンポーネントのIDです。これは、carouselItemCarouselSpinEventを呼び出すと必ず、panelBoxがリフレッシュされ、カレントにされたばかりのアイテムに関する情報が表示されるようになるということを意味しています。部分ページ・レンダリングおよびpartialTriggers属性の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』の「部分ページ・コンテンツのレンダリング」を参照してください。

    例28-14は、図28-6に示すカルーセルのページ・コードを示しています。

    例28-14 部分トリガーにより、表示されているカルーセル・アイテムに合せてフォームが更新される

    <af:carousel
            currentItemKey="#{bindings.Products.treeModel.rootCurrencyRowKey}"
      value="#{bindings.Products.treeModel}" var="item"
      id="c1"
     carouselSpinListener="#{carBean.handleCarouselSpin}">
       <f:facet name="nodeStamp">
         <af:carouselItem id="ci1" text="#{item.ProductName}"
                          binding="#{carBean.carouselItem}">
           <af:image source="/imageservlet?detail=#{item.ProductId}"
                     id="i1"/>
         </af:carouselItem>
       </f:facet>
     </af:carousel>
     <af:panelBox text="PanelBox1" id="pb1" partialTriggers="c1">
       <af:panelFormLayout id="pfl1">
         <af:panelLabelAndMessage label="#{bindings.ProductName.hints.label}"
                                  id="plam2">
           <af:outputText value="#{bindings.ProductName.inputValue}"
                          id="ot4"/>
         </af:panelLabelAndMessage>
    .
    .
    .
    </af:panelBox>
    

28.6.2 カルーセルの作成時に行われる処理

「データ・コントロール」パネルからコレクションをカルーセルとしてドロップすると、ツリーの値バインディングが作成されます。ツリーはノードの階層で構成され、各サブノードは上位レベルのノードから分岐します。

ツリー・バインディングは、イテレータ・バインディングによって公開されたデータ全体を反復します。このカルーセルは、イテレータ・バインディングからの結果セットを、collectionModelの拡張であるtreeModelオブジェクト内にラップします。collectionModelにより、コレクションの各アイテムは、var属性を使用してカルーセル・コンポーネント内で使用できるようになります。ツリー・バインディングの詳細は、23.2.2.1項「表のイテレータと値バインディング」を参照してください。

例28-15に示すように、JDeveloperはcarouselコンポーネントとその子carouselItemコンポーネントの両方をページに追加します。

例28-15 Carouselコンポーネントのページ・コード

<af:carousel
        currentItemKey="#{bindings.Products.treeModel.rootCurrencyRowKey}"
        value="#{bindings.Products.treeModel}" var="item"
        id="c1"
        carouselSpinListener="#{carBean.handleCarouselSpin}">
   <f:facet name="nodeStamp">
     <af:carouselItem id="ci1" text="#{item.ProductName}"/>
   </f:facet>
 </af:carousel>

カルーセルの値は、関連するコレクションのtreeModelにバインドされています。また、カルーセルのcurrentItemKey属性は、バインディング・オブジェクトのrootCurrencyRowKeyにバインドされています。この例では、カルーセルがProductsイテレータ・バインディングのアイテムを反復します。イテレータ・バインディングは、現在の製品を追跡するrowKeySetにバインドします。デフォルトでは、カルーセルのcurrentItemKey属性は、バインディング・オブジェクトのrootCurrencyRowKeyにバインドされています。このため、カルーセルの正面に表示されている製品が、ルートおよびカレント・アイテムになります。carouselItemコンポーネントは、item変数を使用して、カルーセル・タグに表示されているカレント・アイテムのカレント・データ・オブジェクトにアクセスします。

28.7 コンテキスト・イベントの作成

ページまたはページ内のリージョンは、ページの他の場所からの情報または異なるリージョンからの情報を必要とすることがよくあります。情報を取得するためにパラメータを渡すことは可能ですが、それはパラメータが既知であり、EL式でページにアクセスできる入力である場合のみ意味を持ちます。また、パラメータ値が変化した場合にタスク・フローを再起動する必要があるときに、パラメータは便利です。

ただし、複数のページ・フラグメントを持つタスク・フローがあり、ページ・フラグメントには、フロー内のあるページへの入力として使用できる様々な興味深い値が含まれているとします。パラメータを使用して値を渡す場合、タスク・フローはすべてのフラグメントの興味深い各値を結合するための出力パラメータを公開する必要があります。そのかわり、必要な情報を含む各フラグメントに対し、ページを送信すると発生するコンテキスト・イベントを定義できます。情報を必要とするページまたはフラグメントは、様々なイベントをサブスクライブし、イベントを介して情報を取得できます。

たとえばStoreFrontモジュール内で、コンテキスト・イベントを顧客登録ページに使用して、適切な情報トピックを表示できます。ユーザー登録ページregister.jspxには2つのリージョンがあります。1つのリージョンには顧客登録タスク・フローcustomer-registration-task-flow、もう1つのリージョンには情報トピック・タスク・フローhelp-task-flowが含まれます。コンテキスト・イベントは顧客登録リージョンから情報トピック・リージョンに渡され、情報トピック・タスク・フローは情報トピックを表示できるようになります。設計時、例28-16に示すとおり、イベント名、プロデューサ・リージョン、コンシューマ・リージョン、コンシューマ・ハンドラなどの情報がページ定義ファイルのイベント・マップ・セクションに保存されます。

例28-16 registerPageDef.xmlファイルのイベント・マップ

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="queueHelpTopic">
      <producer region="*">
        <consumer region="helptaskflow1"
                  handler="helpPageDef.findHelpTextById">
         <parameters>
            <parameter name="helpTopicId" value="${payLoad}"/>
          </parameters> 
        </consumer>
      </producer> 
    </event>
</eventMap>

実行時に、ユーザーが顧客登録タスク・フローを入力すると、このユーザーはデータを入力し、「次へ」ボタンを押しながら、「基本情報」から「アドレス」まで、その後支払いオプションまでの一連のアクティビティを進めます。ユーザーが「次へ」をクリックすると、payLoadパラメータに伴うコンテキスト・イベントが、顧客登録タスク・フローによりブロードキャストされます。その後、このイベントは情報タスク・フローとそのハンドラhelpPageDef.findHelpTextById()メソッドにより使用されます。このメソッドはpayLoadパラメータを使用して、表示する情報トピック・テキストを決定します。イベント・マップでは、EL式を指定して、入力パラメータをページの変数やパラメータにバインドできます。

イベントは、イベントを発生させるページまたはリージョン(作成者)のページ定義ファイルで構成されます。イベントに基づき処理を実行するコンシューマをプロデューサと関連付けるには、ページ定義にイベント・マップも作成します(リージョン間でイベントを使用するとき、このイベント・マップは、これらのリージョンの両方を保持しているページ定義ファイルに含められます)。使用ページが動的リージョン内にある場合、イベント・マップを使用ページのページ定義ファイル内に配置し、プロデューサの属性リージョンを"*"に設定する必要があります。属性リージョンを"*"に設定するのは、設計時、フレームワークはプロデューサへの相対パスを決定できないためです。

コンテキスト・イベントは、アクション・バインディング、メソッド・アクション・バインディング、値属性バインディング、またはレンジ・バインディング(表、ツリー、またはリスト・バインディング)に対して発生させることができます。また、条件付きでイベントを発生させ、EL式を使用して条件付きでイベントを処理することもできます。

アクション・バインディングとメソッド・アクション・バインディングの場合、アクションまたはメソッドの実行時にイベントは発生します。payLoadには、バインディング・コンテナとイベント・ソース、およびユーザー定義可能なパラメータが1つ含まれます。アクション・バインディングは複数のソースで公開できますが、値属性とリスト・バインディングを公開できるのは1つのソースのみです。

また、ボタンのクリックやメニューからの選択などのADF Facesイベントからコンテキスト・イベントを発生させることもできます。ADF FacesコンポーネントはeventBindingを使用して、コンテキスト・イベント・プロデューサとして動作します。

値属性バインディングの場合、イベントはバインディング・コンテナによってトリガーされ、属性が正常に設定された後に発生します。payLoadには、新しい値、イテレータ、バインディング・コンテナとソース・オブジェクト、およびユーザー定義可能なパラメータが1つ含まれます。例28-17は入力コンポーネントと関連付けられている属性値バインディング内部の値の変更イベントを示します。このページでユーザーがLAST_NAMEの値を変更すると、イベントvalueChangeEventがディスパッチされます。

例28-17 ページ定義ファイルの値属性イベント

<attributeValues IterBinding="DeptView1Iterator" id="Dname"
     xmlns="http://xmlns.oracle.com/adfm/jcuimodel">
    <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
        <event name="valueChangeEvent"/>
     </events>                     
     <AttrNames xmlns="http://xmlns.oracle.com/adfm/uimodel">
        <Item Value="LAST_NAME"/>
      </AttrNames>
</attributeValues>
</bindings>
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="valueChangeEvent">
      <producer region="LAST_NAME">
        <consumer region="" handler="consumeEvent"/>
      </producer>
    </event>
</eventMap>

範囲バインディング(ツリー、表、リスト)の場合、イベントは現行の変更が正常に行われた後に発生します。payLoadには、イテレータ、行キー、バインディング・コンテナとソース・オブジェクト、およびユーザー定義可能なパラメータが1つ含まれます。

値属性バインディングおよび範囲バインディングのコンテキスト・イベントは、ナビゲーションの変化によってトリガーすることもできます。たとえば、ツリー表バインディングの内部にイベントを作成した場合、ユーザーがページでこのツリーの別ノードを選択したときに、このイベントがディスパッチされます。

コンテキスト・イベントの作成、公開、およびサブスクライブには、ページ定義ファイルの「コンテキスト・イベント」タブにある概要エディタを使用します(図28-7を参照)。

図28-7 ページ定義の「コンテキスト・イベント」タブ

ページ定義の「コンテキスト・イベント」タブ

プロパティ・インスペクタの「コンテキスト・イベント」ページを使用して、コンテキスト・イベントを作成、公開、サブスクライブすることもできます。図28-8に示すように、「コンテキスト・イベント」パネルは、ページから適切なコンポーネントを選択した場合のみ表示されます。

図28-8 プロパティ・インスペクタの「コンテキスト・イベント」パネル

コンテキスト・イベントのプロパティ・インスペクタ

コンテキスト・イベントは、ADFビジネス・コンポーネントが発生させるビジネス・イベントや、UIコンポーネントが発生させるイベントとは異なります。この種のイベントの詳細は、Oracle Fusion Middleware Oracle Application Development FrameworkのためのWebユーザー・インタフェース開発者ガイドを参照してください。ただし、コンテキスト・イベントは、UIイベントと関連付けて使用できます。その場合、UIイベントにより起動されるアクション・リスナーが、今度はイベントを発生させるメソッド・アクション・バインディングを起動できます。

28.7.1 コンテキスト・イベントの宣言的作成方法

コンテキスト・イベントを作成するには、まず、アクション、メソッド・アクション、値属性またはリスト・バインディングに基づいて、プロデューサにイベントを作成し、公開します。コンシューマで、このイベントをサブスクライブし、これを処理するためのハンドラを作成します。


注意:

また、次のコールを使用して、コード(たとえば、マネージドBeanの内部)からアクション・コンテキスト・イベントを公開することもできます。

getBindingContainer.raiseEvent(myEventName);

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

コンテキスト・イベントを発生させるために使用するコンポーネントのタイプを決定します。メソッド・アクション・バインディングの使用を計画している場合は、ページにドロップするメソッドをあらかじめ作成しておく必要があります。

通常、タスク・フローおよびビュー・アクティビティを含むリージョンを持つ親ページを作成します。リージョンの1つには、もう1つのリージョンのコンシューマ・イベント・ハンドラのために公開されるコンテキスト・イベントを作成します。タスク・フローとリージョンの使用に関する詳細は、第17章「タスク・フローのリージョンとしての使用」を参照してください。

28.7.1.1 パブリッシャでのコンテキスト・イベントの作成

プロデューサのページにコンテキスト・イベントを作成するには、ページ定義ファイルで概要エディタを使用します。

コンテキスト・イベントを作成するには:

  1. 「プロデューサ」ページで、「データ・コントロール」パネルからコンポーネントをドラッグし、イベントをトリガーするページにドロップします。これにはアクション、メソッド・アクション、値属性またはリスト・バインディングが必要です。StoreFrontモジュールでは、setHelpId()メソッドが「データ・コントロール」パネルからこのページに追加されました。

  2. プロデューサ・ページ定義の概要エディタで、「コンテキスト・イベント」タブを選択します。

  3. 「イベント」セクションで「追加」アイコンをクリックします。

  4. 「コンテキスト・イベントの公開」ダイアログで:

    1. 「新規イベントの作成」を選択します。

    2. イベントの名前を入力します。

    3. payLoadデータをコンシューマに渡す場合は、「次からカスタム値を渡す」を選択します。

    4. payloadデータを渡す場合は、ドロップダウン・リストからデータ型を選択します。

      たとえば、プロデューサ・ページからコンシューマ・ページに属性を渡す場合、「ページ・データ」を選択し、ツリー構造から目的の属性を選択します。

    5. 「呼出し条件」タブにEL式を入力して、条件付きでイベントを発生させることができます。

      たとえば、式${bindings.LAST_NAME.inputValue == 'KING'}を入力すると、顧客の姓が「KING」である場合のみ、イベントが発生します。

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

      イベントはこのページに作成されますが、コンポーネント・バインディングと関連付けるまで公開できません。

      図28-9 コンテキスト・イベントの公開

      コンテキスト・イベントの公開
  5. プロデューサ・ページで、イベントをトリガーするコンポーネントを選択し、プロパティ・インスペクタで「コンテキスト・イベント」ペインを開き、「追加」アイコンをクリックします。

  6. 「コンテキスト・イベントの公開」ダイアログで:

    1. 「既存のイベントの選択」を選択します。

    2. 「名前」フィールドの横の「検索」アイコンをクリックします。

    3. 「コンテキスト・イベントの選択」ダイアログで、ツリー構造から目的のイベントを選択します。このイベントは、ステップ4で作成したものです。

    4. 「OK」をクリックしてから、もう一度「OK」をクリックします。

      これでイベントの公開準備が整いました。

  7. また、ステップ1の説明に従ってページにコンポーネントを追加するときに、このコンポーネントのプロパティ・インスペクタ経由で「コンテキスト・イベントの公開」ダイアログにアクセスすれば、1つのジェスチャーでイベントを作成し、公開できるようにすることができます。ページ定義にイベントを作成すると、そのページのコンポーネントはこのイベントを公開し、また他のページはこのイベントをサブスクライブできるようになります。

28.7.1.2 イベントのサブスクライブと使用

コンテキスト・イベントをサブスクライブするには、親ページのページ定義ファイルで概要エディタを使用します。

イベントをサブスクライブし、使用するには:

  1. 使用ページに、イベントに応答する可能性のあるコンポーネントを追加します。

    StoreFrontモジュールで、findHelpTextByIdメソッド・ハンドラの返したStringは、このページにoutputTextコンポーネントとしてドロップされ、ヘルプ情報を表示します。

  2. イベント処理を行うハンドラと、そのpayLoadデータを作成します。StoreFrontModuleの例では、findHelpTextByIdハンドラ・メソッドが、LookupServiceAMDataControlモジュールに作成されました。EL式をハンドラに追加して、条件付きでページを処理することができます。

  3. コンシューマ・ページ定義の「バインディングと実行可能ファイル」タブの概要エディタで、「バインディング」セクションの「追加」アイコンをクリックします。

  4. 「項目の挿入」ダイアログで、methodActionを選択し、「OK」をクリックします。

  5. 「アクション・バインディングの作成」ダイアログで:

    1. ハンドラを作成したデータ・コレクションを選択します。

    2. 「操作」ドロップダウン・リストから、目的のハンドラを選択します。

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

  6. コンシューマ・ページ定義の「バインディングと実行可能ファイル」タブの概要エディタで、「バインディング」セクションの「追加」アイコンをクリックします。

  7. 「項目の挿入」ダイアログで、attributeValueを選択し、「OK」をクリックします。

  8. 「属性バインディングの作成」ダイアログで:

    1. 「データソース」ドロップダウン・リストから「変数」を選択します。

    2. ハンドラの戻り値に「属性」を選択します。

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

  9. 親ページ定義(両方のリージョンが存在する場所)の概要エディタで、「コンテキスト・イベント」タブに移動し、「イベント」セクションで、「追加」アイコンをクリックします。

  10. 「コンテキスト・イベントの公開」ダイアログで、「既存のイベントの選択」を選択し、「検索」アイコンをクリックします。

  11. 「コンテキスト・イベントの選択」ダイアログで、公開するイベントをツリー構造から選択し、「OK」をクリックします。

  12. 「コンテキスト・イベントの公開」ダイアログで、イベント・パラメータを確認し、「OK」をクリックします。

    イベントが、ページ定義ファイルの概要エディタにある「イベント」リストに表示されます。

  13. 親ページ定義の概要エディタで、「サブスクライバ」をクリックし、「イベント・サブスクライバ」セクションの「追加」アイコンをクリックします。

  14. 「コンテキスト・イベントのサブスクライブ」ダイアログで「検索」アイコンをクリックします。

  15. 「コンテキスト・イベントの選択」ダイアログで、サブスクライブするイベントをツリー構造から選択し、「OK」をクリックします。

  16. 「コンテキスト・イベントのサブスクライブ」ダイアログで:

    1. 「パブリッシャ」ドロップダウン・リストから目的のプロデューサ、または「<任意>」を選択します。1つのコンテキスト・イベントは複数のパブリッシャを持つことができます。

      「<任意>」を選択すると、コンシューマはどのイベントでもサブスクライブできるようになります。ページ定義ファイルで、producer属性にはワイルドカード"*"が設定されます。パブリッシャが動的リージョンである場合、このフィールドを「<任意>」に設定する必要があります。これにより、サブスクライバはどのプロデューサからでも使用できます。

    2. 「範囲」フィールドの隣にある「ハンドラ」アイコンをクリックします。

    3. 「ハンドラの選択」ダイアログで、ツリー構造から目的のイベント・ハンドラを選択し、「OK」をクリックします。

    4. ハンドラがパラメータを必要としている場合は、「パラメータ」タブを選択し、「追加」をクリックしてから、パラメータとして名前/値ペアを入力します。

    5. 条件付きでイベントを処理する場合、「ハンドル」タブを選択し、ハンドラがイベントを処理する条件を決定するEL式を入力します。

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

    図28-10 コンテキスト・イベントのサブスクライブ

    コンテキスト・イベントのサブスクライブ

注意:

構造ウィンドウでページ定義を右クリックし、「イベント・マップの編集」を選択し、イベント・マップを編集することができます。また、ページ定義ファイル、またはプロパティ・インスペクタでイベント属性を編集することもできます。


28.7.2 コンテキスト・イベントの手動作成方法

コンテキスト・イベントの作成では、最初に作成者にイベントを作成します。続いてイベントの使用者を定義し、作成者と使用者をマッピングします。

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

メソッド・バインディング、アクション・バインディング、値属性バインディングまたはリスト・バインディングを持つコンテキスト・イベントをプロデューサ・ページ上に作成します。作成していない場合は、先にバインディングを作成する必要があります。たとえば、メソッド・バインディングの場合は、構造ウィンドウでバインディングを右クリックして「バインディングの内部に挿入」「一般バインディング」「methodAction」を選択し、メソッド・アクション・バインディングを追加します。または、ページ定義ファイルの概要エディタを使用して、バインディングを追加します。その他のバインディングの場合は、入力テキスト、表、ツリーなどのコンポーネントをページにドロップすることが必要な場合があります。

コンテキスト・イベントを作成するには:

  1. イベントのプロデューサのバインディングを含むページ定義ファイルを開きます。

    作成者には、イベントの発行に使用される関連付けられたバインディングが必要です。たとえば、メソッドまたは操作が作成者になる場合、イベントは関連アクション・バインディングまたはメソッド・アクション・バインディングに含まれます。

  2. 構造ウィンドウで、プロデューサのバインディングを右クリックし、「バインディング名の内部に挿入」eventsまたは「バインディング名の内部に挿入」「コンテキスト・イベント」eventsを選択します。

  3. 構造ウィンドウで、たった今作成されたevents要素を右クリックし、「eventsの内部に挿入」→「event」を選択します。

  4. 「eventの挿入」ダイアログで、「名前」フィールドにイベント名を入力し、「終了」をクリックします。

    これで、イベントが作成されます。デフォルトでは、関連するメソッドまたは操作の戻り値はすべて、イベントのペイロードとして取得され、ELでアクセス可能な変数${payLoad}に格納されます。次に、イベントをコンシューマにマッピングし、コンシューマに渡す必要があるペイロードを構成する必要があります。

  5. 使用者へのバインディングを含むページ定義を開きます。

    このページが表すバインディング・コンテナは、含まれるバインディング・コンテナすべてを含む現在のスコープ(タスク・フロー・リージョンなど)からイベントへのアクセスを提供します。リージョンまたは他のネストされたコンテナがイベントを認識する必要がある場合、イベント・マップは使用リージョン内のページのページ定義に存在する必要があります。

  6. 構造ウィンドウで、ページ定義を表す最上位のノードを右クリックし、「イベント・マップの編集」を選択します。


    注意:

    プロデューサ・イベントが埋込み動的リージョン内のページから発生する場合、イベント・マップ・エディタを使用してイベント・マップを編集できないことがあります。イベント・マップは、ページ定義ファイルを編集するか、28.7.5項「イベント・マップの手動による作成方法」で説明しているように「内部に挿入」の手順を使用して、手動で作成できます。


  7. イベント・マップ・エディタで、「追加」アイコンをクリックして、イベント・エントリを追加します。

  8. 「新規EventMapエントリの追加」ダイアログ・ボックスで、次の操作を行います。

    1. 作成者ドロップダウン・メニューを使用して作成者を選択します。

    2. 「イベント名」ドロップダウン・メニューを使用してイベントを選択します。

    3. 使用者ドロップダウン・メニューを使用して使用者を選択します。これは、イベントを使用する実際のメソッドになります。

    4. 使用するメソッドまたは操作にパラメータが必要な場合は、「追加」アイコンをクリックします。

      「パラメータ名」フィールドに、メソッドに必要なパラメータの名前を入力します。「パラメータ値」フィールドに値を入力します。これがイベントからのペイロードとなる場合、${payLoad}式を使用してこの値にアクセスできます。ペイロードに複数のパラメータが含まれ、それらすべてを必要とする場合以外は、省略記号ボタンを使用して「式ビルダー」ダイアログを開きます。このダイアログを使用して、「ペイロード」ノードの下の特定のパラメータを選択できます。

      また、「パラメータ」省略記号ボタンをクリックして、選択ダイアログを開くこともできます。

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

  9. イベント・マップ・エディタで、「OK」をクリックします。

28.7.3 マネージドBeanを使用したコンテキスト・イベントの作成方法

マネージドBeanの内部など、コードからアクション・コンテキスト・イベントを公開することができます。例28-18に示すように、プロデューサ・コンポーネントをマネージドBeanのメソッドに追加します。

この例では、プロデューサはアクション・バインディングを呼び出すコマンド・ボタン、コンシューマは文字列を表示するoutputTextコンポーネントです。これらは両方とも同じページにあります。

例28-18 JSFのイベント・プロデューサとイベント・コンシューマ

<af:form id="f1">
     <af:eventProducerButton value="eventProducerButton1" id="cb1"
                         action="#{MyBean.myActionPerformed}"
                         />
     <af:panelLabelAndMessage label="#{bindings.return.hints.label}"id="plam1">
          <af:outputText value="#{bindings.return.inputValue}" id="ot1"/>
     </af:panelLabelAndMessage>
</af:form>

例28-19に示すとおり、このページ定義ファイルには、プロデューサのメソッド・アクション・バインディング、コンシューマおよびイベント・マップが含まれます

例28-19 イベント・プロデューサ、イベント・コンシューマおよびイベント・マップを含むページ定義

<executables>
    <variableIterator id="variables">
      <variable Type="java.lang.String" Name="eventConsumer_return"
                IsQueriable="false" IsUpdateable="0"
                DefaultValue="${bindings.eventConsumer.result}"/>
    </variableIterator>
</executables>
<bindings>
     <methodAction id="eventProducer"
                  InstanceName="AppModuleDataControl.dataProvider"
                  DataControl="AppModuleDataControl" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="eventProducer"
                  IsViewObjectMethod="false"
                  ReturnName="AppModuleDataControl.methodResults.eventProducer_
                       AppModuleDataControl_dataProvider_eventProducer_result">
            <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
                  <event name="myEvent"/>
            </events>
     </methodAction>
     <methodAction id="eventConsumer" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="eventConsumer"
                  IsViewObjectMethod="false" DataControl="AppModuleDataControl"
                  InstanceName="AppModuleDataControl.dataProvider"
                  ReturnName="AppModuleDataControl.methodResults.eventConsumer_
                        AppModuleDataControl_dataProvider_eventConsumer_result">
               <NamedData NDName="str" NDValue="test" NDType="java.lang.String"/>
    </methodAction>
    <attributeValues IterBinding="variables" id="return">
        <AttrNames>
             <Item Value="eventConsumer_return"/>
        </AttrNames>
    </attributeValues>
</bindings>
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="myEvent">
      <producer region="eventProducer">
        <consumer region="" handler="eventConsumer">
          <parameters>
            <parameter name="test" value="${payLoad}"/>
          </parameters>        
        </consumer>
      </producer>
    </event>
</eventMap>

マネージドBeanで、プロデューサ・メソッド・アクション・バインディングのメソッドを作成します。このメソッドには、コンテキスト・イベントを公開するためのコードが含まれます。例28-20は、myBeanマネージドBeanと、eventProducerコンテキスト・イベントを作成するmyActionPerformedメソッドを示します。

例28-20 コンテキスト・イベントを生成するマネージドBeanコード

public class myBean {
    public myBean() {
    }

public Object myActionPerformed() {
        // Add event code here...
        BindingContainer bc BindingContext.getCurrent().getCurrentBindingsEntry();
        JUCtrlActionBinding actionBnd =
                 (JUCtrlActionBinding)bc.getControlBinding("eventProducer");

        ((DCBindingContainer)bc).getEventDispatcher().queueEvent(actionBnd.
                 getEventProducer(),"myString");

        ((DCBindingContainer)bc).getEventDispatcher().processContextualEvents();
                 return null;
    }
}

このボタンを押すと、myActionPerformedメソッドが呼び出され、コンテキスト・イベントを生成するために次のメソッドがコールされます。

        ((DCBindingContainer)bc).getEventDispatcher().queueEvent(actionBnd.
                 getEventProducer(),"myString");
        ((DCBindingContainer)bc).getEventDispatcher().processContextualEvents();
                 return null;

28.7.4 JavaScriptからのコンテキスト・イベントの作成方法

マネージドBeanからアクセスできるアクションとメソッド・バインディングはすべて、JavaScriptから呼び出すことができます。ADF Facesは、af:serverListener操作コンポーネントを提供します。これは、クライアント側JavaScriptからマネージドBeanメソッドを呼び出すために使用できます。参照されたマネージドBeanメソッドを使用してこのコンポーネントを呼び出すには、BindingContextオブジェクトを使用して、現在のBindingContainerを調べ、OperationBindingまたはJUEventBindingバインディングにアクセスします。また、af:serverListenerコンポーネントを使用して、ブラウザ・クライアントからマネージドBeanメソッドにメッセージpayloadを送信することもできます。

28.7.5 イベント・マップの手動による作成方法

ほとんどの状況では、28.7.2項「コンテキスト・イベントの手動作成方法」の説明に従って、イベント・マップ・エディタを使用してイベント・マップを作成できます。しかし、プロデューサ・イベントが埋込み動的リージョン内のページから発生する場合などの状況では、設計時にイベント・マップ・エディタではイベント・マップの作成に必要な情報を取得できません。

イベント・マップを手動で作成するには:

  1. 使用者へのバインディングを含むページ定義を開きます。

  2. 構造ウィンドウで、ページ定義を表す最上位のノードを右クリックし、pagedef nameの内部に挿入」eventMapを選択します。

    構造ウィンドウにeventMapノードが表示されます。

  3. eventMapノードを選択して右クリックし、「eventMapの内部に挿入」「event」を選択します。

    「eventの挿入」ダイアログで、イベント名を入力して「OK」をクリックします。

    eventノードがeventMapノードの下に表示されます。

    さらにイベントを追加するには、この手順を繰り返します。

  4. eventを選択して右クリックし、「eventの内部に挿入」「producer」を選択します。

    「プロデューサの挿入」ダイアログが表示されます。このイベントを生成しているバインディングの名前を入力します。プロデューサ・リージョンの名前を入力することもできますが、この場合、このタグの下で指定されたコンシューマはすべて、イベントを使用できます。また、"*"を入力して、このタグの下のコンシューマすべてが使用できることを示すこともできます。「OK」をクリックします。

    producerノードがeventノードの下に表示されます。

  5. producerを選択して右クリックし、「producerの内部に挿入」「consumer」を選択します。

    「consumerの挿入」ダイアログが表示されます。このイベントを使用するハンドラ名を入力します。「OK」をクリックします。

    consumerノードがproducerノードの下に表示されます。

    さらにコンシューマを追加するには、この手順を繰り返します。

  6. 渡すパラメータがある場合は、パラメータ名および値を追加します。consumerを選択して右クリックし、「consumerの内部に挿入」「parameters」を選択します。

    parametersノードがconsumerノードの下に表示されます。

    parametersを選択して右クリックし、「parametersの内部に挿入」「parameter」を選択します。

    「parameterの挿入」ダイアログが表示されます。パラメータの名前および値を入力します。値はEL式でもかまいません。「OK」をクリックします。

    さらにパラメータを追加するには、繰り返し「parametersの内部に挿入」「parameter」を選択します。

28.7.6 カスタム・イベント・ディスパッチャの登録方法

デフォルトでは、コンテキスト・イベント・フレームワークはEventDispatcherImplを使用して、リージョンを横断するイベントをディスパッチします。デフォルトのイベント・ディスパッチャをオーバーライドするカスタム動作を提供して、カスタム・イベント・ディスパッチャを作成することができます。デフォルトのディスパッチャをオーバーライドするには、作成したカスタム・イベント・ディスパッチャをDatabindings.cpxファイルに登録する必要があります。

カスタム・イベント・ディスパッチャを登録するには:

  1. EventDispatcherクラスに基づいて、カスタム・イベント・ディスパッチャのJavaクラスを作成します。

  2. 次の形式の完全修飾名を使って、カスタム・イベント・ディスパッチャをDatabindings.cpxファイルに登録します。

    EventDispatcher="package_name.CustomEventDispatcher_name"
    

    例28-21は、パッケージNewPackageに作成されたNewCustomEventDispatcherというカスタム・イベント・ディスパッチャのコードを示します。

    例28-21 Databindings.cpxファイルにカスタム・イベント・ディスパッチャを追加

    <Application xmlns="http://xmlns.oracle.com/adfm/application"
                 version="11.1.1.51.60" id="DataBindings" SeparateXMLFiles="false"
                 Package="project3" ClientType="JClient"
                 EventDispatcher="NewPackage.NewCustomEventDispatcher">
    
  3. プロデューサのページ定義にイベントを作成します。

  4. コンシューマが動的リージョンにある場合は、コンシューマ・リージョンにイベント・マップを作成します。コンシューマが動的リージョンにはない場合でも、プロデューサ・リージョンとコンシューマ・リージョンの両方が入っている親ページにイベント・マップを指定できます。

28.7.7 コンテキスト・イベントの作成時の処理

作成者のイベントを作成すると、JDeveloperはページ定義ファイルにevents要素を追加します。各イベント名が子として追加されます。例28-22に、StoreFrontモジュールのaccount_basicinformationPageDefページ定義ファイルに含まれるsetHelpIdメソッド・アクション・バインディングのイベントを示します。これは、顧客登録タスク・フローの「基本情報」ビューのページ定義です。

例28-22 プロデューサのイベント定義

<methodAction id="setHelpId"
                  InstanceName="LookupServiceAMDataControl.dataProvider"
                  DataControl="LookupServiceAMDataControl"
                  RequiresUpdateModel="true" Action="invokeMethod"
                  MethodName="setHelpId" IsViewObjectMethod="false"
                  ReturnName="LookupServiceAMDataControl.
                      methodResults.setHelpId_
                      LookupServiceAMDataControl_dataProvider_
                      setHelpId_result">
                  <NamedData NDName="usage" NDValue="CREATE_PROFILE"
                       NDType="java.lang.String"/>
 <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
                  <event name="queueHelpTopic"/>
 </events>

メソッド・アクション・バインディングが呼び出されると、イベントがコンシューマにブロードキャストされます。

イベント・マップを構成すると、JDeveloperは対応するページ定義ファイルにイベント・マップのエントリを作成します。例28-23は、customerregistrationtaskflow1リージョンからhelptaskflow1リージョンにqueueHelpTopicイベントをマップするregisterPageDefページ定義ファイル上のイベント・マップを示しています。また、helpPageDefページ定義ファイルで定義されているhelpPageDef.findHelpTextByIdハンドラ・メソッド・バインディングもマップします。コンシューマは、渡されたパラメータに基づいて、表示する情報テキストを決定するメソッドを呼び出します。registerPageDefページ定義はcustomerregistrationtaskflow1およびhelptaskflow1リージョンの両方の親コンテナであるため、マッピングはこのページ定義の中にあります。

例28-23 親ページ定義ファイルのイベント・マップ

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="queueHelpTopic">
      <producer region="*">
        <consumer region="helptaskflow1"
                  handler="helpPageDef.findHelpTextById">
         <parameters>
            <parameter name="helpTopicId" value="${payLoad}"/>
          </parameters> 
        </consumer>
      </producer> 
    </event>
</eventMap>

28.7.8 コンテキスト・イベント・ディスパッチの制御方法

アプリケーション・レベル、またはページ・レベルで、子リージョンへのコンテキスト・イベントのディスパッチを制御できます。アプリケーション・レベルでは、プロデューサがワイルドカードであるeventMapを持つリージョンへのイベントのディスパッチを無効化できます。

アプリケーション・レベルの制御では、例28-24に示すように、adf-config.xmlファイルでdynamicEventSubscriptionsプロパティをfalseに設定します。

例28-24 adf-config.xmlを使用して、アプリケーション・レベルのコンテキスト・イベント・ディスパッチを無効化

<?xml version="1.0" encoding="windows-1252" ?>
<adf-config xmlns="http://xmlns.oracle.com/adf/config"
     xmlns:cef="http://xmlns.oracle.com/adfm/contextualEvent">
     <cef:DynamicRegionEventsConfig dynamicEventSubscriptions="false">
     </cef:DynamicRegionEventsConfig>
</adf-config>

また、例28-25に示すように、関連するページ定義ファイルでDynamicEventSubscriptionsプロパティをfalseに設定して、個々のページに対するコンテキスト・イベントのディスパッチを無効化することもできます。コンテキスト・イベントがこのページや、その子のいずれにも渡されることはありません。

例28-25 ページ定義ファイルを使用して、ページに対するコンテキスト・イベント・ディスパッチを無効化

<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="11.1.1.52.8" id="viewBPageDef" Package="view.pageDefs"
                DynamicEventSubscriptions="false">

28.7.9 実行時に行われる処理: コンテキスト・イベント

イベント・プロデューサとコンシューマの両方が同じページ定義ファイルに定義されている場合、対応するページの呼び出しおよびバインディング・コンテナの作成後、次の場合にイベントが発生します。

  • 対応するメソッドまたはアクション・バインディングが実行される

  • 値バインディングが正常に設定される

  • レンジ・バインディングの現行性が正常に設定される

メソッド・バインディングの場合、メソッド実行の結果がイベントのペイロードを形成し、イベントがキューイングされます。JSFライフサイクルのアプリケーションの起動フェーズで、キューイングされたすべてのイベントがディスパッチされます。バインディング・コンテナに関連付けられたイベント・ディスパッチャは、そのイベントに関連するコンシューマをイベント・マップで確認し、イベントをコンシューマに渡します(イベント・マップは同じページ定義ファイルの一部であるため、バインディング・コンテナにも含まれます)。その後、ペイロードはキューから削除されます。

プロデューサとコンシューマが異なるリージョンに存在する場合、イベントは最初に同じコンテナ内の任意のコンシューマにディスパッチされ、次にイベント伝播が親バインディング・コンテナに委任されます。この処理は、親または最上位のバインディング・コンテナに達するまで続きます。最上位バインディング・コンテナに達した後、プロデューサがワイルドカード(*)に設定されているページでリージョンを保持する子バインディング・コンテナにイベントは再度ディスパッチされます。

28.8 ADFモデル・レイヤー検証の追加

Modelレイヤーでは、ADFモデル検証規則を特定のページのバインディングの属性として設定できます。ユーザーがフィールド内のデータを編集または入力してフォームを送信したときに、設定した規則および条件に対してバインドされたデータが検証されます。検証が失敗すると、アプリケーションによりエラー・メッセージが表示されます。

エンティティ・オブジェクトのビジネス・ドメイン・レイヤーに検証規則をすでに設定している場合は、ADFモデル検証を追加する必要はありません。ADFビジネス・コンポーネント・ベースのFusion Webアプリケーションでは、アプリケーション・モジュールのデータ・コントロール以外のデータ・コントロールを使用しないかぎり、ADFモデル検証を使用する必要はありません。

skipValidationプロパティをtrueに設定すると、ADFモデル検証をバイパスできます。skipValidationskipDataControlsに設定して、トランザクションを検証せずに、バインド・オブジェクトを検証できます。たとえば、データ入力を受け付けるポップアップ・ウィンドウを開く表アクションがあるときに、表でコミットする前にビュー・レイヤーでこれらの入力を検証できるようにしたい場合は、skipValidationskipDataControlsに設定します。構造ウィンドウでページ定義ファイルのルート・ノードを選択すると、skipValidationプロパティがプロパティ・インスペクタに表示されます。

28.8.1 検証の追加方法

ADFモデル検証をページ定義ファイルに設定します。検証規則を定義し、規則に違反した場合に表示するエラー・メッセージを設定します。

表28-4に、バインディングの属性に対して構成できるADFモデル検証規則を示します。

表28-4 ADFモデル検証規則

バリデータ規則名 説明

比較

属性の値とリテラル値を比較する。

リスト

値が値リスト内にあるかどうかを検証する

レンジ

値が値範囲内にあるかどうかを検証する。

長さ

値の文字またはバイト・サイズをサイズおよびオペランド(greater than or equal toなど)に対して検証する。

正規表現

Java正規表現構文を使用してデータを検証する。

必須

属性にその値が存在するかどうかを検証する。


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

ページにコンポーネントを作成します。このコンポーネントにはバインディング属性が必要です。

ADFモデル検証規則を作成するには:

  1. 規則を作成するバインディングが含まれるページ定義を開きます。

  2. 構造ウィンドウで、属性、リストまたは表バインディングを選択します。

  3. プロパティ・インスペクタで、「詳細」に続いて「検証ルールの編集」を選択します。

  4. 「検証ルールの編集」ダイアログで「バインディング」ノードを展開し、属性名を選択して、「新規」をクリックします。

  5. 「検証ルールの追加」ダイアログで、検証規則を選択し、それに応じて規則を構成します。

  6. 「失敗処理」タブを選択して、規則に違反した場合に表示するメッセージを構成します。

28.8.2 実行時に行われる処理: Model検証規則

ユーザーがデータを送信すると、送信された値がNULL以外の値か、少なくとも1つの文字からなる文字列値であった場合、コンポーネントに設定されているすべてのバリデータが1つずつコールされます。コンポーネントのf:validatorタグはバインディングのvalidatorプロパティにバインドされるため、モデルに設定されている検証ルーチンがアクセスされて実行されます。

続いて、プロセスは次のコンポーネントに進みます。すべての検証が正常に完了すると、モデル値更新フェーズが開始され、ローカル値を使用してモデルが更新されます。いずれかの検証が失敗すると、現在のページがエラー・メッセージとともに再表示されます。

28.9 エラー・メッセージの表示

「データ・コントロール」パネルを使用して入力コンポーネントを作成すると、ページの最上部にaf:messagesタグが挿入されます。このタグにより、サーバー側で行われた検証に対するキュー内のすべてのエラー・メッセージを、色でオフセットされたボックス内に表示できます。ADF Facesのクライアント側検証を無効にするように選択した場合、これらのエラー・メッセージがADFモデルのエラー・メッセージとともに表示されます。ADFモデルのメッセージが最初に表示されます。メッセージは、af:messagesタグ内に、関連付けられたコンポーネントとともに表示されます。

図28-11は、ユーザーが入力した値が許容されないことを示す、ADFモデル検証規則に対するエラー・メッセージを示しています。

図28-11 Modelエラー・メッセージの表示

Model側エラー・メッセージ

af:messagesタグを使用して、ページ最上部のボックス内にサーバー側のエラー・メッセージを表示できます。「データ・コントロール」パネルからアイテムを入力コンポーネントとしてページにドロップすると、このタグが自動的に追加されます。

エラー・ボックス内にエラー・メッセージを表示するには:

  1. 構造ウィンドウでaf:messagesタグを選択します。

    このタグは、「データ・コントロール」パネルから入力ウィジェットをドロップすると必ず自動的に作成されます。ただし、タグを手動で挿入する必要がある場合は、例28-26に示すように、コードをaf:documentタグ内に追加するだけです。

    例28-26 ページのメッセージ・タグ

    <af:document>
      <af:messages globalOnly="false" />
      ...
    </af:document>
    
  2. 「プロパティ・インスペクタ」で次の属性を設定します。

    • globalOnly: デフォルトでは、ADF Facesによってグローバル・メッセージ(コンポーネントに関連付けられていないメッセージ)が表示され、続いて個別のコンポーネント・メッセージが表示されます。ボックス内にグローバル・メッセージのみを表示する場合は、属性をtrueに設定します。その場合も、関連付けられたコンポーネントの傍にコンポーネント・メッセージが表示されます。

    • Inline: メッセージ・リストのインラインをページとレンダリングするかまたはポップアップ・ウィンドウ内でレンダリングするかを指定します。

    • message: メッセージ・ボックス・タイトルのすぐ下、個別メッセージのリストの上に表示されるメイン・メッセージ・テキスト。

  3. クライアント側の検証が無効になっていることを確認します。クライアント側の検証を無効にしていない場合、ADF Faces検証エラーがあるときは常にアラート・ダイアログが表示され、エラーはサーバーに伝播されなくなります。

    クライアント側の検証を無効にするには、例28-27に示すように、trinidad-config.xmlファイルで<client-validation-disable>のエントリを追加し、trueに設定します。

    例28-27 Trinidad-config.xmlでのクライアント側の検証の無効化

    <?xml version="1.0" encoding="windows-1252"?>
    <trinidad-config xmlns="http://myfaces.apache.org/trinidad/config">
      <skin-family>blafplus-rich</skin-family>
      <client-validation-disabled>true</client-validation-disabled>
    </trinidad-config>
    

28.10 エラー処理のカスタマイズ

デフォルトのDCErrorHandlerImplクラスを拡張するカスタム・エラー・ハンドラを使用して、エラーをレポートできます。カスタム例外ハンドラ・クラスを登録するためにコードを記述する必要はありません。かわりに、構造ウィンドウでDataBindings.cpxファイルのルート・ノードを選択した後、プロパティ・インスペクタを使用してErrorHandlerClassプロパティに、使用するエラー・ハンドラの完全修飾名を設定します。

カスタム・エラー・ハンドラには、次の上書き可能なメソッドを含めることができます。

例28-28は、DCErrorHandlerImplクラスを拡張したカスタム・エラー・ハンドラです。この例は、ユーザーに対して表示されるリストに登場すべきでない例外をスキップするために必要なskipException()メソッドに対するオーバーライドを示しています。

例28-28 カスタム・エラー・ハンドラ

package view.controller.fwkext;

import java.sql.SQLIntegrityConstraintViolationException;

import java.util.ArrayList;
import java.util.List;

import oracle.adf.model.binding.DCBindingContainer; 
import oracle.adf.model.binding.DCErrorHandlerImpl;

import oracle.jbo.CSMessageBundle; 
import oracle.jbo.DMLConstraintException; 
import oracle.jbo.JboException;

public class CustomErrorHandler extends DCErrorHandlerImpl {

   List<ExceptionMapper> exceptionMapperList = new ArrayList<ExceptionMapper>();
   public CustomErrorHandler() {
     this(true);
   }

   public CustomErrorHandler(boolean setToThrow) {
     super(setToThrow); 
     exceptionMapperList.add(new DisableJboExceptionCodesMapper());
   }

   public void reportException(DCBindingContainer bc, Exception ex) { 
     for (ExceptionMapper mapper : exceptionMapperList) {
       if (mapper.canMapException(ex)) { 
         ex = mapper.mapException(ex);
       } 
     }
     super.reportException(bc, ex);
   }

   /**
    * If an exception is a RowValException or a TxnValException and they
    * have nested exceptions, then do not display it. This example shows
    * an implementation that skips the SQLIntegrityConstraintViolationException
    * from displaying in the error final list displayed to the user.
    */
   @Override
   protected boolean skipException(Exception ex) {

      if (ex instanceof DMLConstraintException) {
            return false;
        } else if (ex instanceof SQLIntegrityConstraintViolationException) {
            return true;
        }
        return super.skipException(ex);
    }

}

コンストラクタをMyErrorHandler()に変更する必要があります。例外エラー・ハンドラには、例28-29に示すように、デフォルトのコンストラクタが必要です。

例28-29 デフォルトのコンストラクタ

ErrorHandlerClass="viewcontroller.MyErrorHandler" public MyErrorHandler()  {   super(true); }

28.10.1 メッセージの詳細部分のカスタマイズ方法

メッセージの詳細部分をカスタマイズし、使用する予定のある場合は、このメッセージを取得し、処理するために、カスタム・エラー・ハンドラを作成し、getDetailedDisplayMessageメソッドを実装することができます。最終的なメッセージは、ビュー・レイヤーに渡され、他のメッセージと統合されます。

メッセージの詳細部分をカスタマイズするには:

  1. デフォルトのDCErrorHandlerImplクラスを拡張するカスタム・エラー・ハンドラを作成します。

  2. このクラスで、DCErrorMessageオブジェクトを戻すgetDetailedDisplayMessageメソッドをオーバーライドします。

    例28-30に、カスタム・エラー・ハンドラ・クラスでのgetDetailedDisplayMessageメソッドの実装を示します。

    例28-30 getDetailDisplayMessageメソッドを使ったカスタム・エラー・ハンドラ・クラス

    public final class MyErrorMessageHandler extends DCErrorHandlerImpl {
        public MyErrorMessageHandler (){
            super(false);
        }
        public DCErrorMessage getDetailedDisplayMessage(BindingContext ctx,
                                                        RegionBinding ctr,
                                                        Exception ex) {
            ...
            return new MyDCErrorMesssage(ctr, ex);
        }
    }
    
  3. DCErrorMessageインタフェースを実装するカスタム・クラスを作成します。このクラスはgetHTMLTextメソッドおよびgetTextメソッドを実装する必要があります。

    getHTMLTextメソッドに、実際の処理を実行するためのコードを追加しますが、インタフェースの要件を満たすには、getTextの実装も必要です。

  4. getHTMLTextの実装では、エラー・メッセージを作成、処理するためのコードを追加します。

    getDetailedDisplayMessagegetHTMLTextは、エラー・メッセージの最終版をHTMLフラグメントとして戻す必要があります。このフラグメントは、ページのHTMLコードに挿入されます。このため、getDetailedDisplayMessageによりメッセージが戻される前に、テキスト・メッセージに対して、必要な前処理をすべて実行しておく必要があります。たとえば、ローカライズしたメッセージの取得や、メッセージの順番を右から左に変更するなどの処理が必要である場合は、メッセージが戻される前に行います。

    例28-31はこのインタフェースの実装を示しています。

    例28-31 DCErrorMessageインタフェースの実装

    public final class MyDCErrorMesssage implements DCErrorMessage {
        RegionBinding m_regionBinding;
        Exception m_ex;
           public MyDCErrorMesssage(RegionBinding ctr, Exception ex) {
            super();
            this.m_regionBinding = ctr;
            this.m_ex = ex;
        }
        public String getText() {
            ...
            return "Message String";
        }
        public String getHTMLText() {
            ...
            /* Add code to process the message, including localization */
            /* and right-to-left directional requirements. */
            /* Return the message as the finalized HTML fragment.*/
            return "<html><b>error</b> message details</html>";
        }
    }
    

    HTMLタグを使用してメッセージを書式化するには、例に示すように、メッセージを<html></html>タグで囲む必要があります。エラー・メッセージでは次のHTMLタグのみを使用できます。

    • <span>

    • <b>

    • <a>

    • <i>

    • <em>

    • <br>

    • <hr>

    • <li>

    • <ol>

    • <ul>

    • <p>

    • <tt>

    • <big>

    • <small>

    • <pre>

28.10.2 複数スレッドを処理するエラー・ハンドラの記述方法

Oracle ADFでは、作成されるBindingContextオブジェクトごとにカスタム・エラー・ハンドラのインスタンスを1つ作成します。Oracle ADFでは、同じ論理エンド・ユーザー・セッションからの同時Webリクエストをシリアライズするため、通常、複数スレッドは同じエラー・ハンドラを同時に使用しません。しかし、スレッドセーフのカスタム・エラー・ハンドラを保証するには、JboExceptionsetProperty() APIを使用します。このメソッドは、表示用に例外がJSF FacesMessageオブジェクトに変換されるときに、後で必要になる可能性があるヒントをすべて例外オブジェクト自体に格納します。