Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド 11gリリース1 (11.1.1.7.0) B52028-05 |
|
前 |
次 |
この章では、ADFデータ・バインディングを使用して、Fusion Webアプリケーションのページに複雑な機能を追加する方法を説明します。フォームおよびコマンド・コンポーネントを作成するためのパラメータを取るメソッドの使用方法についても説明します。また、コンテキスト・イベントの作成およびADFモデル・レベルの検証の使用に関する情報を示します。
この章の内容は次のとおりです。
注意: この章で説明する実装メソッドのいくつかは、ページレベルの設計のためのものです。タスク・フローを使用している場合は、同じ機能の多くを実行できます。詳細は、第14章「ADFタスク・フローの概説」を参照してください。 |
基本的なページを作成してナビゲーション機能を追加すると、ページ間でパラメータを渡したり、宣言アクションを上書きする機能を提供するなどの、より複雑な機能を追加できます。Oracle ADFには、このような複雑な機能を実際のコードをほとんど使用せずに追加できる機能が数多く用意されています。
この章で説明する機能のいくつかは、他のメソッドでも実行できます。たとえば、個別のページ・フローではなくタスク・フローを使用している場合、タスク・フローのパラメータ渡しメカニズムを使用する必要があります。あるいは、ADFビジネス・コンポーネントを使用している場合は、ADFモデル検証規則ではなく、データ・モデル・プロジェクトにあるエンティティ・オブジェクトの検証規則を使用する必要があります。ビジネス・コンポーネントの検証規則の詳細は、第7章「検証とビジネス・ルールの宣言的な定義」を参照してください。
アプリケーションにカスタム・メソッドが含まれている場合、これらのメソッドは「データ・コントロール」パネルに表示されます。これらのメソッドは、コマンド・ボタンとしてドラッグ・アンド・ドロップできます。ユーザーがボタンをクリックすると、メソッドが実行されます。
カスタム・メソッドの作成の詳細は、9.7項「サービス・メソッドによるアプリケーション・モジュールのカスタマイズ」および9.9項「UIクライアントへのカスタム・サービス・メソッドの公開」を参照してください。
たとえば、Fusion Order DemoアプリケーションのStoreFrontモジュールのアプリケーション・モジュールにはupdateItemInCart(Integer, Integer, Boolean)
メソッドが含まれています。このメソッドは、ショッピング・カート内の項目を更新します。ユーザーがこのメソッドを実行できるようにするには、図28-1のように、「データ・コントロール」パネルからupdateItemInCart(Integer, Integer Boolean)
メソッドをドラッグします。
要求されるビジネス・ロジックを実行するために、多くのメソッドでは、そのパラメータ(1つ以上)に対する値を必要とします。つまり、メソッドにバインドされたボタンを作成する際に、パラメータの値の取得元を指定する必要があります。
作業を始める前に、次のようにします。
ページに追加できるカスタム・メソッドを作成します。
たとえば、updateItemInCart(Integer, Integer, Boolean)
メソッドを使用する場合、更新するアイテムを指定する必要があります。
メソッドにバインドされたボタンを追加するには:
「データ・コントロール」パネルから、メソッドをページにドラッグします。
ヒント: 表またはフォームに含まれるデータを使用するメソッドのボタンをドロップする場合は、その表またはフォームの中にボタンをドロップする必要があります。 |
ポップアップ・メニューから「作成」>→「メソッド」>→「ADFボタン」を選択します。
メソッドがパラメータを取る場合は、「アクション・バインディングの編集」ダイアログが開きます。「アクション・バインディングの編集」ダイアログで、各パラメータの値を入力するか、「パラメータ」の「値」列で「EL式ビルダーの表示」メニュー選択をクリックし、EL式ビルダーを起動します。
メソッドをコマンド・ボタンとしてドロップすると、JDeveloperによって次の処理が行われます。
メソッドのメソッド・アクション・バインディングが定義されます。
メソッドがパラメータを取得する場合は、パラメータ値を保持するNamedData
要素が作成されます。
ADF Facesコマンド・コンポーネント用のコードがJSFページに挿入されます。
actionListener
を使用して、ボタンにメソッドをバインドします。
メソッド・コールからの戻り値を使用します。
JDeveloperはメソッドにアクション・バインディングを追加します。アクション・バインディングはRequiresUpdateModel
プロパティを使用して、アクションを実行する前にモデルを更新する必要があるかどうかを判別します。コマンド操作の場合、デフォルトではこのプロパティはtrue
に設定されています。つまり、ビュー・レイヤーでのすべての変更は、操作を実行する前にモデルに移動する必要があります。
パラメータを取得するメソッドを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>
JDeveloperはADF Facesコンポーネント用のコードをJSFページに追加します。22.4.2.3項「EL式を使用したナビゲーション操作へのバインド」で説明されているとおり、このコードは、他のどのコマンド・ボタンのコードとも同じです。ただし、このボタンは、組込み操作に対するアクション・バインディングのexecute
メソッドではなく、ドロップされたメソッドに対するメソッド・アクション・バインディングのexecute
メソッドにバインドされます。
操作を使用してコマンド・ボタンを作成するときと同様に、メソッドを使用してコマンド・ボタンを作成すると、actionListener
属性を使用して、ボタンがメソッドに自動的にバインドされます。ボタンは、EL式を使用して、指定されたメソッドのアクション・バインディングのexecute
プロパティにバインドされます。このEL式により、アプリケーション・モジュールに対してバインディングのメソッドが起動します。コマンド・ボタンのactionListener
属性の詳細は、22.4.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が付けられます。たとえば、 |
メソッド・コールからの戻り値を使用することもできます。例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」を戻します。
1つのページでのアクションに対して、アプリケーション機能を判別するためのパラメータを設定する必要が生じる場合があります。たとえば、あるページから別のページの結果表へ移動する検索コマンド・ボタンを作成できます。ただし、結果表が表示されるのはパラメータ値がfalse
の場合のみです。
ページ間でこのパラメータを渡す場合やパラメータ値のチェックに使用するメソッドを含める場合には、マネージドBeanを使用できます。検索ページのレンダリング時にマネージドBeanがインスタンス化され、このBeanのメソッドによってこのパラメータがチェックされます。このパラメータがnull
の場合(ページが初めてレンダリングされる場合)は、値がtrue
に設定されます。
カスタム・メソッドの作成の詳細は、9.7項「サービス・メソッドによるアプリケーション・モジュールのカスタマイズ」および9.9項「UIクライアントへのカスタム・サービス・メソッドの公開」を参照してください。
type
プロパティがaction
に設定されたsetPropertyListener
コンポーネント(この検索を実行したコマンド・ボタンにネストされている)を使用してこのフラグがfalse
に設定されるため、検索の実行後に結果表が表示されるようになります。マネージドBeanの使用の詳細は、20.4項「Fusion WebアプリケーションでのマネージドBeanの使用」を参照してください。
setPropertyListener
コンポーネントを使用して、その他のオブジェクトの値を設定できます。このコンポーネントは、コマンド・コンポーネントの子である必要があります。
作業を始める前に、次のようにします。
ページにコマンド・コンポーネントを作成します。
setPropertyListenerコンポーネントを使用するには:
コンポーネント・パレットの「操作」パネルからsetPropertyListenerコンポーネントをドラッグして、子としてコマンド・コンポーネントにドロップします。
または、このコンポーネントを右クリックし、「ボタンの内部に挿入」→「ADF Faces」→setPropertyListenerを選択します。
「プロパティ・リスナーの設定の挿入」ダイアログの「選択元」フィールドにパラメータ値を入力します。
「先」フィールドにパラメータのターゲットを入力します。
ヒント: 作成されるページのページ定義ファイルに直接パラメータ値を設定するかわりに、マネージドBeanまたはスコープにパラメータ値を格納することを考慮してください。次のページに直接設定すると、それ以降、ナビゲーションを簡単に変更できなくなります。詳細は、20.4項「Fusion WebアプリケーションでのマネージドBeanの使用」を参照してください。また、バインディング・コンテナ内のデータは、コンテナが準備されたリクエスト中にのみ有効です。データを設定してから次のページがレンダリングされるまでの間に、データが変更される場合があります。 |
「タイプ」ドロップダウン・メニューから「アクション」を選択します。
「OK」をクリックします。
setPropertyListener
コンポーネントを使用すると、次のページに移動する前にコマンド・コンポーネントによって値が設定されます。渡す必要がある値のソースまたは実際の値をfrom
属性に設定すると、コンポーネントからその値へのアクセスが可能になります。to
属性をターゲットに設定すると、コマンド・コンポーネントによってターゲットに値が設定されるようになります。例28-5に、false
値を取得し、その値をsearchResults
マネージドBeanのinitialSearch
フラグの値として設定するコマンド・コンポーネントのJSFページのコードを示します。
ユーザーがコマンド・コンポーネントをクリックすると、移動する前に、setPropertyListener
コンポーネントによってパラメータ値が設定されます。例28-5では、setPropertyListener
はfalse
値を取得し、その値をsearchResults
マネージドBeanのinitialSearch
属性の値として設定しています。これで、レンダリングするかどうかを決定するためにこの値を認識する必要があるコンポーネントは、EL式#{searchResults.initialSearch}
を使用してアクセスできます。
操作またはメソッドをコマンド・ボタンとしてドロップすると、操作またはメソッドのexecute
メソッドに、そのボタンが自動的にバインドされます。ただし、既存のロジックの前または後に、ロジックの追加が必要になる場合もあります。
Jdeveloperを使用すると、バインディング・コンテナにアクセスするマネージドBeanでメソッドおよびプロパティを新規作成することにより、宣言的操作にロジックを追加できます。デフォルトでは、この生成されたコードによって、操作またはメソッドが実行されます。その後、このコードの前か後にロジックを追加できます。元の操作またはメソッドのexecute
プロパティではなく、この新規メソッドにコマンド・コンポーネントが自動的にバインドされます。その後、ユーザーがボタンをクリックすると、新規メソッドが実行されます。
たとえば、Fusion Order Demoアプリケーションの注文ページのCommit
操作には、追加処理が必要です。「コミット」ボタンは「発注」に名前が変更され、orderPageBean
マネージドBeanのsubmitOrders
メソッドにロジックが追加されます。
宣言メソッドを上書きするには、マネージドBeanにコマンド・コンポーネントがバインドされる新規メソッドを保持させる必要があります。ページにバッキングBeanが関連付けられている場合は、JDeveloperによって、バインディング・オブジェクトへのアクセスに必要なコードがバッキングBeanに追加されます。ページにバッキングBeanが関連付けられていない場合は、作成を促す指示が表示されます。
作業を始める前に、次のようにします。
マネージドBeanで宣言メソッドをオーバーライドするメソッドを作成します。操作はデフォルトで使用できます。
注意: 現在、コマンド・コンポーネントの |
宣言メソッドを上書きのするには:
上書きする操作またはメソッドをJSFページ上にドラッグし、UIコマンド・コンポーネントとしてドロップします。
コンポーネントが作成され、ActionListener
属性を使用してADFモデル・レイヤーの関連するバインディング・オブジェクトにバインドされます。
「データ・コントロール」パネルでメソッドを使用したコマンド・コンポーネントの作成の詳細は、28.2項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。
操作によるコマンド・コンポーネントの作成の詳細は、22.4.2項「コマンド・ボタンの作成時の処理」を参照してください。
JSFページでコンポーネントをダブルクリックします。
「バインド・アクション・プロパティ」ダイアログで、次のいずれかの方法で、バッキングBeanとコンポーネントのバインド先とするメソッドを指定します。
自動バインディングがそのページで有効化されている場合は、図28-2のように、バッキングBeanはすでに自動選択されています。
新規メソッドを作成するには、「メソッド」フィールドにメソッドの名前を入力します。このフィールドには、最初にデフォルト名が表示されています。
または
既存のメソッドを使用するには、「メソッド」フィールドのドロップダウン・リストからメソッドを選択します。
「ADFバインディング・コードの生成」を選択します。
そのページで自動バインディングが使用されていない場合は、図28-3のように、既存のバッキングBeanから選択するか、新規作成できます。
「新規」をクリックして、新しいバッキングBeanを作成します。「マネージドBeanの作成」ダイアログで、Beanおよびクラスに名前を付け、Beanのスコープを設定します。
または
既存のバッキングBeanおよびメソッドをドロップダウン・リストから選択します。
注意: コマンド・コンポーネントに |
バッキング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; } }
これで、例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
のままになります。
宣言メソッドをオーバーライドすると、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}"/>
ヒント: 上書き後のメソッドを使用するボタンをクリックすると、次のエラーが表示されます。
これは、上書き後のメソッドを含むマネージドBeanのスコープが、 |
ADF Facesには、作成されたアクティビティを日、週、月単位のビューに表示するカレンダ・コンポーネントが含まれています。図28-4に、いくつかのサンプル・アクティビティがある週表示モードのADF Faces Calendarを示します。
このコンポーネントには、次の機能も含まれています。
月単位、週単位、日単位、およびリスト・ビューを切り替えるためのツールバー。
ヒント: これらのツールバー・ボタンを使用すると、Calendarの属性値が変わります。この値が保持されるように構成し、特定のユーザーがカレンダにアクセスしたときには必ずその値で表示されるようにすることができます。詳細は、第35章「実行時でのユーザー・カスタマイズの許可」を参照してください。 |
週のはじめの曜日および1日の開始時刻の設定。たとえば、カレンダの1週間は日曜日に、1日は8:00 amから始まるように設定できます。
スキニング・キーを使用した構成可能なスタイル。
さらに、その他のADF Facesコンポーネントやリッチ・クライアント・フレームワークを使用して、次の機能を実装することもできます。
ポップアップ機能。サポートされているフェースに配置されたコンポーネント。ある特定のイベントに応答し、ユーザーがアクティビティやカレンダに従って行動できるようにします。たとえば、ユーザーがCalendar内のアクティビティをクリックすると、CalendarActivityEvent
が起動され、ActivityDetail
ファセットにあるポップアップ・コンポーネントがすべて表示されます。図28-5に示すように、ユーザーがアクティビティを表示および編集できるフォームを含んでいるダイアログ・コンポーネントを使用することもできます。
ドラッグ・アンド・ドロップ機能: calendarDropTarget
タグを追加して、ユーザーがアクティビティをカレンダの別の場所にドラッグできるようにすることができます。その後、アクティビティで実際に時刻が変更され、データ・ストアに保持されるように機能を実装します。
ツールバーのカスタマイズ: デフォルトでは、ツールバーにはユーザーがビューを切り替えるためのボタンとともに、「前へ」、「次へ」ボタンや現在の日付に戻るためのボタンが含まれます。また、このツールバーには現在の日付範囲(日表示の場合は日付)が表示されます。ユーザーが選択したボタンを含むファセットを追加して、ツールバーをカスタマイズすることができます。
スキニング: カレンダはスキニング・キーを使用して、使用する色やアイコンなどを決定できます。スキンを拡張して、カレンダの外観を変更できます。
組込み機能の構成や、追加機能の実装に関する詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』の「カレンダ・アプリケーションの作成」の章に説明されています。
ADF Faces CalendarコンポーネントはCalendarModel
クラスにバインドする必要があります。このクラスは、ユーザーがADFビジネス・コンポーネントを使用して、カレンダ・データを管理するときに、このユーザーのために作成することができます。たとえば、日付、時刻、件名、場所、所有者など、アクティビティの詳細を表すデータがデータ・ストアに入っているとします。このデータを表すエンティティ・オブジェクトを作成してから、このデータを表示するためのビュー・オブジェクトを作成した場合、関連するコレクションを「データ・コントロール」パネルからドラッグ・アンド・ドロップして、カレンダを作成できます。JDeveloperはモデルを宣言的に作成して、このモデルにビューをバインドし、カレンダを起動したときに正しいデータが表示されるようにします。ただし、モデルを作成するためには、ADFビジネス・コンポーネントを持つデータ・モデル・プロジェクトのエンティティ・オブジェクトおよび同じプロジェクト内のビュー・オブジェクトに、有効日指定の属性が必要です。また、ビュー・オブジェクトには、指定された日付範囲に対する正しいアクティビティを返すように問合せを修正するための変数も必要です。
JSFページでカレンダを作成する前に、まず、カレンダの属性を表す具体的な属性を持つエンティティ・オブジェクトを作成する必要があります。その後、このエンティティ・オブジェクトからビュー・オブジェクトを作成し、表示する日付範囲と現在のタイムゾーンを表す名前付きバインド変数を使用して、問合せを編集してください。これにより、この問合せから、カレンダの指定されたビューに表示すべきアクティビティのみが返されるようになります。
たとえば、あるアクティビティを表すデータベース表があるとします。これには、タイトル列、開始時刻、終了時刻、所有者を表すプロバイダ・オブジェクトへの参照が含まれています。この表に基づいて、(次の手順で説明するとおり、要件を満たすことを保証しながら)エンティティ・オブジェクトとビュー・オブジェクトを作成します。その後、ビュー・オブジェクトに、カレンダに現在表示されている開始時刻と終了時刻を表す名前付きバインド変数、カレンダで現在使用されているタイムゾーンを追加します。これにより、問合せはその時間範囲内に収まるアクティビティのみを返すようになります。
JSFページにカレンダ・コンポーネントを追加すると、これを構成して、必要な機能をさらに追加できるようになります。
ADF Faces Calendarを作成するには:
データ・ソースに基づいて、エンティティ・オブジェクトを作成します。このエンティティ・オブジェクトには、表28-1に示す属性が含まれていなければなりません。これらの属性は、必ずしも、この表に示す名前を使用する必要はありません。どのような名前でもつけられます。ただし、記載されているタイプのいずれかでなければなりません。後述の手順で、これらの属性を、CalendarModel
の属性にマップします。
表28-1 カレンダに必須の属性
属性 | 有効なタイプ | 説明 |
---|---|---|
開始時刻 |
|
アクティビティの開始時刻 |
終了時刻 |
|
アクティビティの開始時刻 |
ID |
|
一意のID |
プロバイダID |
|
アクティビティの所有者を表すプロバイダ・オブジェクトのID |
タイトル |
|
アクティビティの簡単な説明 |
このエンティティ・オブジェクトも、表28-2に示す既知の属性を含むことができます(必須ではありません)。
表28-2 カレンダに必要に応じて指定できる属性
属性 | タイプ | 説明 |
---|---|---|
繰返し |
|
アクティビティの繰返しステータス。有効な値は |
アラーム |
|
アクティビティに関連付けられたアラームがあるかどうか。有効な値は |
時間タイプ |
|
アクティビティに関連付けられている時間のタイプ。有効値は |
場所 |
|
アクティビティの場所。 |
タグ |
|
アクティビティのキーワード |
エンティティ・オブジェクトは、CalendarModel
が認識していない属性を含むこともできます。これらの属性は、後述の手順でカスタム・プロパティとしてモデルに追加できます。
エンティティ・オブジェクトの作成の詳細は、第4章「エンティティ・オブジェクトを使用したビジネス・ドメイン・レイヤーの作成」を参照してください。
関連するビュー・オブジェクトを作成します。概要エディタの「問合せ」ページで、次に対する名前付きバインド変数を作成します。
タイムゾーンを表す文字列
カレンダに表示されている現在の日付範囲の開始日を表す日付
カレンダに表示されている現在の日付範囲の終了日を表す日付
ヒント: ADF Facesカレンダの日付は「半分空いている」状態です。つまり、カレンダは、開始時刻ちょうど、またはそれ以降に始まり、終了時刻前に(ちょうどではない)アクティビティすべてを戻します。 |
名前付きバインド変数の作成の詳細は、5.10項「バインド変数の使用」を参照してください。
アクティビティのプロバイダ(所有者)を表すエンティティ・オブジェクトを作成します。このエンティティ・オブジェクトには、表28-3に示す属性が含まれていなければなりません。これらの属性は、必ずしも、この表に示す名前を使用する必要はありません。どのような名前でもつけられます。ただし、記載されているタイプでなければなりません。後述の手順で、これらの属性を、CalendarProvider
の属性にマップします。
このプロバイダのビュー・オブジェクトを作成します。
新しいビュー・オブジェクトがアプリケーション・モジュールの一部であることを確認し、必要に応じて、「データ・コントロール」パネルをリフレッシュします。
20.3項「Webページの作成」の手順に従って、JSFページを作成します。
「データ・コントロール」パネルから、ステップ2で作成したアクティビティに対応するビュー・オブジェクトを表すコレクションをドラッグし、カレンダとしてドロップします。
「カレンダ・バインディング」ダイアログで、CalendarModel
およびCalendarProvider
クラスにバインド変数と属性をマップします。詳細は、「ヘルプ」をクリックするか、[F1]を押してください。
デフォルトでは、カレンダは読取り専用で、そのときにデータ・ストアに入っているアクティビティのみが返されます。『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』の「カレンダ・アプリケーションの作成」の章に説明されている手順に従って、カレンダを構成し、その他の機能を実装する必要があります。
たとえば、新しいアクティビティを作成できるようにするには、カレンダの作成に使用したものと同じデータ・コントロールを使用し、(『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のダイアログの作成方法に関する項の説明に従って)ダイアログで入力フォームを作成します。入力フォームの作成に関する詳細は、22.6項「入力フォームの作成」を参照してください。
コレクションをカレンダとしてドロップすると、JDeveloperにより次の処理が行われます。
アクティビティ・コレクションへのイテレータ・バインディングを1つと、プロバイダ・コレクションへのイテレータ・バインディングを1つ定義します。
アクティビティ・コレクションでexecuteWithParams
操作へのアクション・バインディングを定義します。表示するアクティビティを返す問合せの実行のために呼び出されるのはこの操作です。この操作には日付範囲とタイムゾーンを決定するためのパラメータが必要であるため、(ビュー・オブジェクトで名前付きバインド変数として作成された)パラメータそれぞれについて、NamedData
要素も作成されます。NamedData
要素の詳細は、28.2.2.2項「メソッドでのパラメータの使用方法」を参照してください。
カレンダ・バインディングを定義します。このバインディングは、ウィザードで定義したとおり、コレクションの行を表すnode
要素を含み、データ・コントロール属性をカレンダ・アクティビティの属性にマップします。value
はデータ・コントロール属性、type
はカレンダ属性です。カスタム定義属性では、type
はcustom
、value
はデータ・コントロール属性になります。各行(ノード)はrowKey
で表されます。これはアクティビティIDです。
また、利用可能なプロバイダのソースとマッピングを決定するproviderDefinition
要素もあります。このマッピングにより、カレンダ・モデルはプロバイダの状態(有効または無効)に基づいてアクティビティをフィルタできるようになります。
ヒント: カスタム属性にアクセスするには、 |
例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
クラスを使用します。
カレンダにアクセスすると、executeWithParams
操作が、カレンダ・コンポーネントのview
およびactiveDay
属性により決定されるstartDate
およびendDate
パラメータ値を使って呼び出されます。たとえば、view
属性がmonth
、activeDay
が当日の日付(ここでは、2009年2月6日とします)に設定されている場合、startDate
の値はFebruary 1, 2009
、endDate
の値はFebruary 28, 2009
になります。デフォルトでは、タイムゾーン値はtrinidad-config.xml
ファイルのtime-zone
設定から取得されます(詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のtrinidad-config.xmlでの構成に関する項を参照してください)。したがって、問合せは、この日付範囲内に収まるアクティビティのみを返すように制限されます。
カレンダ・コンポーネントはCalendarModel
にバインドされているため、問合せがデータを返すとき、CalendarModel
はCalendarActivityDefinition
クラスを使用して、カレンダ・バインディング・クラスにアクセスし、このバインディングが提供するマッピングを使用して、データ・ソースからカレンダに値をマップします。
図28-6に示すように、イメージを回転カルーセルに表示できます。正面にある画像を変更するには、下部のスライダを使用するか、または別の画像を正面にドラッグします。
表示されるイメージごとに子carouselItem
コンポーネントを組み込み、これらのコンポーネントを個々のイメージにバインドするかわりに、carousel
コンポーネントを完成コレクションにバインドし、ツリーがデータの各行をスタンプ処理するのと同じ方法で、各アイテムの値をスタンプ処理して、1つのcarouselItem
コンポーネントを繰り返しレンダリングします。各項目にスタンプが設定されると、現在の項目のデータが、carousel
コンポーネントvar
属性を使用するEL式を使用して特定可能なプロパティにコピーされます。カルーセルのレンダリングが完了したら、このプロパティは削除されるか前の値に戻ります。カルーセルはnodeStamp
ファセットを持っています。このファセットは、各アイテムに関するテキストと簡単な説明の表示に使用されるcarouselItem
コンポーネントのホルダーで、各アイテムについて表示されるイメージの親コンポーネントでもあります。Carouselコンポーネントの詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のカルーセルでの画像の表示に関する項を参照してください。
Fusion WebアプリケーションでCarouselコンポーネントを使用する場合、「データ・コントロール」パネルを使用して、コンポーネントを作成します。また、カルーセルのスピン・イベントの処理にはマネージドBeanを使用します。その他のロジックについては、アイテムの表示が必要になる可能性があります。
作業を始める前に、次のようにします。
カルーセルに表示されるコレクションに対するビュー・オブジェクトを作成します。このビュー・オブジェクトには少なくとも次のアイテムに対する属性を組み込む必要があります。
タイトル。これは、カルーセル内の画像の下に表示されます。
簡単な説明。これは、ユーザーが画像にマウスを重ねたときに表示されるテキストに使用されます。
データバインドされたCarouselコンポーネントを作成するには:
「データ・コントロール」パネルから、ビュー・オブジェクトで使用されるコレクションをページにドラッグし、ポップアップ・メニューから「カルーセル」を選択します。
プロパティ・インスペクタの「動作」セクションで、ロジックを実行し、カルーセルを回転させる必要のあるときに、この回転を処理するハンドラ・メソッドに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; }
プロパティ・インスペクタの「拡張」セクションで、バインディング属性のドロップダウン・メニューをクリックし、「編集」を選択します。「属性の編集:バインディング」ダイアログで、ステップ2で作成したマネージドBeanを選択します。新しいプロパティcarousel
を作成します。これにより、ハンドラ・メソッドがCarouselオブジェクトにアクセスできるようになります。
構造ウィンドウで、carousel
コンポーネントとnodeStamp
ファセットを展開し、carouselItem
コンポーネントを選択します。
CarouselItem
コンポーネントのtext
属性を、カルーセルのvar
属性で設定されている変数値(デフォルトではitem
)を使用して、データ・モデルの関連するプロパティにバインドします。したがって、carouselItem
のtext
属性の値はitem.title
になります(title
がデータ・モデルのカルーセル・アイテムで使用されるテキストへのアクセスに使用されるプロパティである場合)。
Products
ビュー・オブジェクトを使用していた場合、この値は#{item.ProductName}
になります。
プロパティ・インスペクタの「拡張」セクションで、バインディング属性のドロップダウン・メニューをクリックし、「編集」を選択します。「属性の編集:バインディング」ダイアログで、ステップ2で作成したマネージドBeanを選択します。新しいプロパティcarouselItem
を作成します。
コンポーネント・パレットの「ADF Faces」ページで、「共通コンポーネント」パネルから、Imageをドラッグし、carouselItem
の子としてドロップします。
「イメージの挿入」ダイアログに、画像ソースへのパスを入力します。必ず、カルーセルでこのアイテムを表している変数を使用してください。たとえば、この製品の画像ファイルへのパスは通常、次のようになります。
/imageservlet?detail=#{Products.ProductId}
カルーセル内の画像については、次を使用します。
/imageservlet?detail=#{item.ProductId}
carousel
およびcarouselItem
コンポーネントのその他の属性の設定に関する詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド』のカルーセルの作成方法に関する項を参照してください。
カルーセル内のアイテムに関する追加情報を提供する場合は、同じビュー・オブジェクトをドラッグし、たとえばフォームとしてページにドロップすることができます。カルーセルが回転したら、そのときに表示されているアイテムの情報が再表示させるようにするには、フォーム内のコンポーネントで、このフォームが含まれるコンポーネントのpartialTrigger
属性にCarouselコンポーネントのIDを設定する必要があります。
たとえば、図28-6にある各アイテムの情報を表示するフォームはpanelBox
コンポーネントに含まれています。panelBox
コンポーネントのpartialTrigger
属性はc1
に設定されていますが、これはこのCarouselコンポーネントのIDです。これは、carouselItem
がCarouselSpinEvent
を呼び出すと必ず、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>
「データ・コントロール」パネルからコレクションをカルーセルとしてドロップすると、ツリーの値バインディングが作成されます。ツリーはノードの階層で構成され、各サブノードは上位レベルのノードから分岐します。
ツリー・バインディングは、イテレータ・バインディングによって公開されたデータ全体を反復します。このカルーセルは、イテレータ・バインディングからの結果セットを、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
変数を使用して、カルーセル・タグに表示されているカレント・アイテムのカレント・データ・オブジェクトにアクセスします。
ページまたはページ内のリージョンは、ページの他の場所からの情報または異なるリージョンからの情報を必要とすることがよくあります。情報を取得するためにパラメータを渡すことは可能ですが、それはパラメータが既知であり、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-8に示すように、「コンテキスト・イベント」パネルは、ページから適切なコンポーネントを選択した場合のみ表示されます。
コンテキスト・イベントは、ADFビジネス・コンポーネントが発生させるビジネス・イベントや、UIコンポーネントが発生させるイベントとは異なります。この種のイベントの詳細は、Oracle Fusion Middleware Oracle Application Development FrameworkのためのWebユーザー・インタフェース開発者ガイドを参照してください。ただし、コンテキスト・イベントは、UIイベントと関連付けて使用できます。その場合、UIイベントにより起動されるアクション・リスナーが、今度はイベントを発生させるメソッド・アクション・バインディングを起動できます。
コンテキスト・イベントを作成するには、まず、アクション、メソッド・アクション、値属性またはリスト・バインディングに基づいて、プロデューサにイベントを作成し、公開します。コンシューマで、このイベントをサブスクライブし、これを処理するためのハンドラを作成します。
注意: また、次のコールを使用して、コード(たとえば、マネージドBeanの内部)からアクション・コンテキスト・イベントを公開することもできます。 getBindingContainer.raiseEvent(myEventName); |
作業を始める前に、次のようにします。
コンテキスト・イベントを発生させるために使用するコンポーネントのタイプを決定します。メソッド・アクション・バインディングの使用を計画している場合は、ページにドロップするメソッドをあらかじめ作成しておく必要があります。
通常、タスク・フローおよびビュー・アクティビティを含むリージョンを持つ親ページを作成します。リージョンの1つには、もう1つのリージョンのコンシューマ・イベント・ハンドラのために公開されるコンテキスト・イベントを作成します。タスク・フローとリージョンの使用に関する詳細は、第17章「タスク・フローのリージョンとしての使用」を参照してください。
プロデューサのページにコンテキスト・イベントを作成するには、ページ定義ファイルで概要エディタを使用します。
コンテキスト・イベントを作成するには:
「プロデューサ」ページで、「データ・コントロール」パネルからコンポーネントをドラッグし、イベントをトリガーするページにドロップします。これにはアクション、メソッド・アクション、値属性またはリスト・バインディングが必要です。StoreFrontモジュールでは、setHelpId()
メソッドが「データ・コントロール」パネルからこのページに追加されました。
プロデューサ・ページ定義の概要エディタで、「コンテキスト・イベント」タブを選択します。
「イベント」セクションで「追加」アイコンをクリックします。
「コンテキスト・イベントの公開」ダイアログで:
「新規イベントの作成」を選択します。
イベントの名前を入力します。
payLoadデータをコンシューマに渡す場合は、「次からカスタム値を渡す」を選択します。
payloadデータを渡す場合は、ドロップダウン・リストからデータ型を選択します。
たとえば、プロデューサ・ページからコンシューマ・ページに属性を渡す場合、「ページ・データ」を選択し、ツリー構造から目的の属性を選択します。
「呼出し条件」タブにEL式を入力して、条件付きでイベントを発生させることができます。
たとえば、式${bindings.LAST_NAME.inputValue == 'KING'}
を入力すると、顧客の姓が「KING」である場合のみ、イベントが発生します。
「OK」をクリックします。
イベントはこのページに作成されますが、コンポーネント・バインディングと関連付けるまで公開できません。
プロデューサ・ページで、イベントをトリガーするコンポーネントを選択し、プロパティ・インスペクタで「コンテキスト・イベント」ペインを開き、「追加」アイコンをクリックします。
「コンテキスト・イベントの公開」ダイアログで:
「既存のイベントの選択」を選択します。
「名前」フィールドの横の「検索」アイコンをクリックします。
「コンテキスト・イベントの選択」ダイアログで、ツリー構造から目的のイベントを選択します。このイベントは、ステップ4で作成したものです。
「OK」をクリックしてから、もう一度「OK」をクリックします。
これでイベントの公開準備が整いました。
また、ステップ1の説明に従ってページにコンポーネントを追加するときに、このコンポーネントのプロパティ・インスペクタ経由で「コンテキスト・イベントの公開」ダイアログにアクセスすれば、1つのジェスチャーでイベントを作成し、公開できるようにすることができます。ページ定義にイベントを作成すると、そのページのコンポーネントはこのイベントを公開し、また他のページはこのイベントをサブスクライブできるようになります。
コンテキスト・イベントをサブスクライブするには、親ページのページ定義ファイルで概要エディタを使用します。
イベントをサブスクライブし、使用するには:
使用ページに、イベントに応答する可能性のあるコンポーネントを追加します。
StoreFrontモジュールで、findHelpTextById
メソッド・ハンドラの返したStringは、このページにoutputText
コンポーネントとしてドロップされ、ヘルプ情報を表示します。
イベント処理を行うハンドラと、そのpayLoadデータを作成します。StoreFrontModuleの例では、findHelpTextById
ハンドラ・メソッドが、LookupServiceAMDataControl
モジュールに作成されました。EL式をハンドラに追加して、条件付きでページを処理することができます。
コンシューマ・ページ定義の「バインディングと実行可能ファイル」タブの概要エディタで、「バインディング」セクションの「追加」アイコンをクリックします。
「項目の挿入」ダイアログで、methodActionを選択し、「OK」をクリックします。
「アクション・バインディングの作成」ダイアログで:
ハンドラを作成したデータ・コレクションを選択します。
「操作」ドロップダウン・リストから、目的のハンドラを選択します。
「OK」をクリックします。
コンシューマ・ページ定義の「バインディングと実行可能ファイル」タブの概要エディタで、「バインディング」セクションの「追加」アイコンをクリックします。
「項目の挿入」ダイアログで、attributeValueを選択し、「OK」をクリックします。
「属性バインディングの作成」ダイアログで:
「データソース」ドロップダウン・リストから「変数」を選択します。
ハンドラの戻り値に「属性」を選択します。
「OK」をクリックします。
親ページ定義(両方のリージョンが存在する場所)の概要エディタで、「コンテキスト・イベント」タブに移動し、「イベント」セクションで、「追加」アイコンをクリックします。
「コンテキスト・イベントの公開」ダイアログで、「既存のイベントの選択」を選択し、「検索」アイコンをクリックします。
「コンテキスト・イベントの選択」ダイアログで、公開するイベントをツリー構造から選択し、「OK」をクリックします。
「コンテキスト・イベントの公開」ダイアログで、イベント・パラメータを確認し、「OK」をクリックします。
イベントが、ページ定義ファイルの概要エディタにある「イベント」リストに表示されます。
親ページ定義の概要エディタで、「サブスクライバ」をクリックし、「イベント・サブスクライバ」セクションの「追加」アイコンをクリックします。
「コンテキスト・イベントのサブスクライブ」ダイアログで「検索」アイコンをクリックします。
「コンテキスト・イベントの選択」ダイアログで、サブスクライブするイベントをツリー構造から選択し、「OK」をクリックします。
「コンテキスト・イベントのサブスクライブ」ダイアログで:
「パブリッシャ」ドロップダウン・リストから目的のプロデューサ、または「<任意>」を選択します。1つのコンテキスト・イベントは複数のパブリッシャを持つことができます。
「<任意>」を選択すると、コンシューマはどのイベントでもサブスクライブできるようになります。ページ定義ファイルで、producer
属性にはワイルドカード"*"が設定されます。パブリッシャが動的リージョンである場合、このフィールドを「<任意>」に設定する必要があります。これにより、サブスクライバはどのプロデューサからでも使用できます。
「範囲」フィールドの隣にある「ハンドラ」アイコンをクリックします。
「ハンドラの選択」ダイアログで、ツリー構造から目的のイベント・ハンドラを選択し、「OK」をクリックします。
ハンドラがパラメータを必要としている場合は、「パラメータ」タブを選択し、「追加」をクリックしてから、パラメータとして名前/値ペアを入力します。
条件付きでイベントを処理する場合、「ハンドル」タブを選択し、ハンドラがイベントを処理する条件を決定するEL式を入力します。
「OK」をクリックします。
注意: 構造ウィンドウでページ定義を右クリックし、「イベント・マップの編集」を選択し、イベント・マップを編集することができます。また、ページ定義ファイル、またはプロパティ・インスペクタでイベント属性を編集することもできます。 |
コンテキスト・イベントの作成では、最初に作成者にイベントを作成します。続いてイベントの使用者を定義し、作成者と使用者をマッピングします。
作業を始める前に、次のようにします。
メソッド・バインディング、アクション・バインディング、値属性バインディングまたはリスト・バインディングを持つコンテキスト・イベントをプロデューサ・ページ上に作成します。作成していない場合は、先にバインディングを作成する必要があります。たとえば、メソッド・バインディングの場合は、構造ウィンドウでバインディングを右クリックして「バインディングの内部に挿入」→「一般バインディング」→「methodAction」を選択し、メソッド・アクション・バインディングを追加します。または、ページ定義ファイルの概要エディタを使用して、バインディングを追加します。その他のバインディングの場合は、入力テキスト、表、ツリーなどのコンポーネントをページにドロップすることが必要な場合があります。
コンテキスト・イベントを作成するには:
イベントのプロデューサのバインディングを含むページ定義ファイルを開きます。
作成者には、イベントの発行に使用される関連付けられたバインディングが必要です。たとえば、メソッドまたは操作が作成者になる場合、イベントは関連アクション・バインディングまたはメソッド・アクション・バインディングに含まれます。
構造ウィンドウで、プロデューサのバインディングを右クリックし、「バインディング名の内部に挿入」→eventsまたは「バインディング名の内部に挿入」→「コンテキスト・イベント」→eventsを選択します。
構造ウィンドウで、たった今作成されたevents要素を右クリックし、「eventsの内部に挿入」→「event」を選択します。
「eventの挿入」ダイアログで、「名前」フィールドにイベント名を入力し、「終了」をクリックします。
これで、イベントが作成されます。デフォルトでは、関連するメソッドまたは操作の戻り値はすべて、イベントのペイロードとして取得され、ELでアクセス可能な変数${payLoad}
に格納されます。次に、イベントをコンシューマにマッピングし、コンシューマに渡す必要があるペイロードを構成する必要があります。
使用者へのバインディングを含むページ定義を開きます。
このページが表すバインディング・コンテナは、含まれるバインディング・コンテナすべてを含む現在のスコープ(タスク・フロー・リージョンなど)からイベントへのアクセスを提供します。リージョンまたは他のネストされたコンテナがイベントを認識する必要がある場合、イベント・マップは使用リージョン内のページのページ定義に存在する必要があります。
構造ウィンドウで、ページ定義を表す最上位のノードを右クリックし、「イベント・マップの編集」を選択します。
注意: プロデューサ・イベントが埋込み動的リージョン内のページから発生する場合、イベント・マップ・エディタを使用してイベント・マップを編集できないことがあります。イベント・マップは、ページ定義ファイルを編集するか、28.7.5項「イベント・マップの手動による作成方法」で説明しているように「内部に挿入」の手順を使用して、手動で作成できます。 |
イベント・マップ・エディタで、「追加」アイコンをクリックして、イベント・エントリを追加します。
「新規EventMapエントリの追加」ダイアログ・ボックスで、次の操作を行います。
作成者ドロップダウン・メニューを使用して作成者を選択します。
「イベント名」ドロップダウン・メニューを使用してイベントを選択します。
使用者ドロップダウン・メニューを使用して使用者を選択します。これは、イベントを使用する実際のメソッドになります。
使用するメソッドまたは操作にパラメータが必要な場合は、「追加」アイコンをクリックします。
「パラメータ名」フィールドに、メソッドに必要なパラメータの名前を入力します。「パラメータ値」フィールドに値を入力します。これがイベントからのペイロードとなる場合、${payLoad}
式を使用してこの値にアクセスできます。ペイロードに複数のパラメータが含まれ、それらすべてを必要とする場合以外は、省略記号ボタンを使用して「式ビルダー」ダイアログを開きます。このダイアログを使用して、「ペイロード」ノードの下の特定のパラメータを選択できます。
また、「パラメータ」省略記号ボタンをクリックして、選択ダイアログを開くこともできます。
「OK」をクリックします。
イベント・マップ・エディタで、「OK」をクリックします。
マネージド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;
マネージドBeanからアクセスできるアクションとメソッド・バインディングはすべて、JavaScriptから呼び出すことができます。ADF Facesは、af:serverListener
操作コンポーネントを提供します。これは、クライアント側JavaScriptからマネージドBeanメソッドを呼び出すために使用できます。参照されたマネージドBeanメソッドを使用してこのコンポーネントを呼び出すには、BindingContext
オブジェクトを使用して、現在のBindingContainer
を調べ、OperationBinding
またはJUEventBinding
バインディングにアクセスします。また、af:serverListener
コンポーネントを使用して、ブラウザ・クライアントからマネージドBeanメソッドにメッセージpayload
を送信することもできます。
ほとんどの状況では、28.7.2項「コンテキスト・イベントの手動作成方法」の説明に従って、イベント・マップ・エディタを使用してイベント・マップを作成できます。しかし、プロデューサ・イベントが埋込み動的リージョン内のページから発生する場合などの状況では、設計時にイベント・マップ・エディタではイベント・マップの作成に必要な情報を取得できません。
イベント・マップを手動で作成するには:
使用者へのバインディングを含むページ定義を開きます。
構造ウィンドウで、ページ定義を表す最上位のノードを右クリックし、「pagedef nameの内部に挿入」→eventMapを選択します。
構造ウィンドウにeventMapノードが表示されます。
eventMapノードを選択して右クリックし、「eventMapの内部に挿入」→「event」を選択します。
「eventの挿入」ダイアログで、イベント名を入力して「OK」をクリックします。
eventノードがeventMapノードの下に表示されます。
さらにイベントを追加するには、この手順を繰り返します。
eventを選択して右クリックし、「eventの内部に挿入」→「producer」を選択します。
「プロデューサの挿入」ダイアログが表示されます。このイベントを生成しているバインディングの名前を入力します。プロデューサ・リージョンの名前を入力することもできますが、この場合、このタグの下で指定されたコンシューマはすべて、イベントを使用できます。また、"*"を入力して、このタグの下のコンシューマすべてが使用できることを示すこともできます。「OK」をクリックします。
producerノードがeventノードの下に表示されます。
producerを選択して右クリックし、「producerの内部に挿入」→「consumer」を選択します。
「consumerの挿入」ダイアログが表示されます。このイベントを使用するハンドラ名を入力します。「OK」をクリックします。
consumerノードがproducerノードの下に表示されます。
さらにコンシューマを追加するには、この手順を繰り返します。
渡すパラメータがある場合は、パラメータ名および値を追加します。consumerを選択して右クリックし、「consumerの内部に挿入」→「parameters」を選択します。
parametersノードがconsumerノードの下に表示されます。
parametersを選択して右クリックし、「parametersの内部に挿入」→「parameter」を選択します。
「parameterの挿入」ダイアログが表示されます。パラメータの名前および値を入力します。値はEL式でもかまいません。「OK」をクリックします。
さらにパラメータを追加するには、繰り返し「parametersの内部に挿入」→「parameter」を選択します。
デフォルトでは、コンテキスト・イベント・フレームワークはEventDispatcherImpl
を使用して、リージョンを横断するイベントをディスパッチします。デフォルトのイベント・ディスパッチャをオーバーライドするカスタム動作を提供して、カスタム・イベント・ディスパッチャを作成することができます。デフォルトのディスパッチャをオーバーライドするには、作成したカスタム・イベント・ディスパッチャをDatabindings.cpx
ファイルに登録する必要があります。
カスタム・イベント・ディスパッチャを登録するには:
EventDispatcher
クラスに基づいて、カスタム・イベント・ディスパッチャのJavaクラスを作成します。
次の形式の完全修飾名を使って、カスタム・イベント・ディスパッチャをDatabindings.cpx
ファイルに登録します。
EventDispatcher="package_name
.CustomEventDispatcher_name
"
例28-21は、パッケージNewPackage
に作成されたNewCustomEventDispatcher
というカスタム・イベント・ディスパッチャのコードを示します。
プロデューサのページ定義にイベントを作成します。
コンシューマが動的リージョンにある場合は、コンシューマ・リージョンにイベント・マップを作成します。コンシューマが動的リージョンにはない場合でも、プロデューサ・リージョンとコンシューマ・リージョンの両方が入っている親ページにイベント・マップを指定できます。
作成者のイベントを作成すると、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>
アプリケーション・レベル、またはページ・レベルで、子リージョンへのコンテキスト・イベントのディスパッチを制御できます。アプリケーション・レベルでは、プロデューサがワイルドカードである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
に設定して、個々のページに対するコンテキスト・イベントのディスパッチを無効化することもできます。コンテキスト・イベントがこのページや、その子のいずれにも渡されることはありません。
イベント・プロデューサとコンシューマの両方が同じページ定義ファイルに定義されている場合、対応するページの呼び出しおよびバインディング・コンテナの作成後、次の場合にイベントが発生します。
対応するメソッドまたはアクション・バインディングが実行される
値バインディングが正常に設定される
レンジ・バインディングの現行性が正常に設定される
メソッド・バインディングの場合、メソッド実行の結果がイベントのペイロードを形成し、イベントがキューイングされます。JSFライフサイクルのアプリケーションの起動フェーズで、キューイングされたすべてのイベントがディスパッチされます。バインディング・コンテナに関連付けられたイベント・ディスパッチャは、そのイベントに関連するコンシューマをイベント・マップで確認し、イベントをコンシューマに渡します(イベント・マップは同じページ定義ファイルの一部であるため、バインディング・コンテナにも含まれます)。その後、ペイロードはキューから削除されます。
プロデューサとコンシューマが異なるリージョンに存在する場合、イベントは最初に同じコンテナ内の任意のコンシューマにディスパッチされ、次にイベント伝播が親バインディング・コンテナに委任されます。この処理は、親または最上位のバインディング・コンテナに達するまで続きます。最上位バインディング・コンテナに達した後、プロデューサがワイルドカード(*
)に設定されているページでリージョンを保持する子バインディング・コンテナにイベントは再度ディスパッチされます。
Modelレイヤーでは、ADFモデル検証規則を特定のページのバインディングの属性として設定できます。ユーザーがフィールド内のデータを編集または入力してフォームを送信したときに、設定した規則および条件に対してバインドされたデータが検証されます。検証が失敗すると、アプリケーションによりエラー・メッセージが表示されます。
エンティティ・オブジェクトのビジネス・ドメイン・レイヤーに検証規則をすでに設定している場合は、ADFモデル検証を追加する必要はありません。ADFビジネス・コンポーネント・ベースのFusion Webアプリケーションでは、アプリケーション・モジュールのデータ・コントロール以外のデータ・コントロールを使用しないかぎり、ADFモデル検証を使用する必要はありません。
skipValidation
プロパティをtrue
に設定すると、ADFモデル検証をバイパスできます。skipValidation
をskipDataControls
に設定して、トランザクションを検証せずに、バインド・オブジェクトを検証できます。たとえば、データ入力を受け付けるポップアップ・ウィンドウを開く表アクションがあるときに、表でコミットする前にビュー・レイヤーでこれらの入力を検証できるようにしたい場合は、skipValidation
をskipDataControls
に設定します。構造ウィンドウでページ定義ファイルのルート・ノードを選択すると、skipValidation
プロパティがプロパティ・インスペクタに表示されます。
ADFモデル検証をページ定義ファイルに設定します。検証規則を定義し、規則に違反した場合に表示するエラー・メッセージを設定します。
表28-4に、バインディングの属性に対して構成できるADFモデル検証規則を示します。
表28-4 ADFモデル検証規則
バリデータ規則名 | 説明 |
---|---|
比較 |
属性の値とリテラル値を比較する。 |
リスト |
値が値リスト内にあるかどうかを検証する |
レンジ |
値が値範囲内にあるかどうかを検証する。 |
長さ |
値の文字またはバイト・サイズをサイズおよびオペランド(greater than or equal toなど)に対して検証する。 |
正規表現 |
Java正規表現構文を使用してデータを検証する。 |
必須 |
属性にその値が存在するかどうかを検証する。 |
作業を始める前に、次のようにします。
ページにコンポーネントを作成します。このコンポーネントにはバインディング属性が必要です。
ADFモデル検証規則を作成するには:
規則を作成するバインディングが含まれるページ定義を開きます。
構造ウィンドウで、属性、リストまたは表バインディングを選択します。
プロパティ・インスペクタで、「詳細」に続いて「検証ルールの編集」を選択します。
「検証ルールの編集」ダイアログで「バインディング」ノードを展開し、属性名を選択して、「新規」をクリックします。
「検証ルールの追加」ダイアログで、検証規則を選択し、それに応じて規則を構成します。
「失敗処理」タブを選択して、規則に違反した場合に表示するメッセージを構成します。
ユーザーがデータを送信すると、送信された値がNULL以外の値か、少なくとも1つの文字からなる文字列値であった場合、コンポーネントに設定されているすべてのバリデータが1つずつコールされます。コンポーネントのf:validator
タグはバインディングのvalidator
プロパティにバインドされるため、モデルに設定されている検証ルーチンがアクセスされて実行されます。
続いて、プロセスは次のコンポーネントに進みます。すべての検証が正常に完了すると、モデル値更新フェーズが開始され、ローカル値を使用してモデルが更新されます。いずれかの検証が失敗すると、現在のページがエラー・メッセージとともに再表示されます。
「データ・コントロール」パネルを使用して入力コンポーネントを作成すると、ページの最上部にaf:messages
タグが挿入されます。このタグにより、サーバー側で行われた検証に対するキュー内のすべてのエラー・メッセージを、色でオフセットされたボックス内に表示できます。ADF Facesのクライアント側検証を無効にするように選択した場合、これらのエラー・メッセージがADFモデルのエラー・メッセージとともに表示されます。ADFモデルのメッセージが最初に表示されます。メッセージは、af:messages
タグ内に、関連付けられたコンポーネントとともに表示されます。
図28-11は、ユーザーが入力した値が許容されないことを示す、ADFモデル検証規則に対するエラー・メッセージを示しています。
af:messages
タグを使用して、ページ最上部のボックス内にサーバー側のエラー・メッセージを表示できます。「データ・コントロール」パネルからアイテムを入力コンポーネントとしてページにドロップすると、このタグが自動的に追加されます。
エラー・ボックス内にエラー・メッセージを表示するには:
構造ウィンドウでaf:messagesタグを選択します。
このタグは、「データ・コントロール」パネルから入力ウィジェットをドロップすると必ず自動的に作成されます。ただし、タグを手動で挿入する必要がある場合は、例28-26に示すように、コードをaf:document
タグ内に追加するだけです。
「プロパティ・インスペクタ」で次の属性を設定します。
globalOnly: デフォルトでは、ADF Facesによってグローバル・メッセージ(コンポーネントに関連付けられていないメッセージ)が表示され、続いて個別のコンポーネント・メッセージが表示されます。ボックス内にグローバル・メッセージのみを表示する場合は、属性をtrue
に設定します。その場合も、関連付けられたコンポーネントの傍にコンポーネント・メッセージが表示されます。
Inline: メッセージ・リストのインラインをページとレンダリングするかまたはポップアップ・ウィンドウ内でレンダリングするかを指定します。
message: メッセージ・ボックス・タイトルのすぐ下、個別メッセージのリストの上に表示されるメイン・メッセージ・テキスト。
クライアント側の検証が無効になっていることを確認します。クライアント側の検証を無効にしていない場合、ADF Faces検証エラーがあるときは常にアラート・ダイアログが表示され、エラーはサーバーに伝播されなくなります。
クライアント側の検証を無効にするには、例28-27に示すように、trinidad-config.xml
ファイルで<client-validation-disable>
のエントリを追加し、true
に設定します。
デフォルトのDCErrorHandlerImpl
クラスを拡張するカスタム・エラー・ハンドラを使用して、エラーをレポートできます。カスタム例外ハンドラ・クラスを登録するためにコードを記述する必要はありません。かわりに、構造ウィンドウでDataBindings.cpx
ファイルのルート・ノードを選択した後、プロパティ・インスペクタを使用してErrorHandlerClass
プロパティに、使用するエラー・ハンドラの完全修飾名を設定します。
カスタム・エラー・ハンドラには、次の上書き可能なメソッドを含めることができます。
reportException()
: 発生した例外をレポートするためにコールされます。レポートされた例外を分析するように上書きできます。
getDisplayMessage()
: 発生したエラーごとにJSFにレポートされるメッセージを戻します。カスタム・エラー・ハンドラで特定の例外をクライアントにレポートする必要がない場合は、null
を戻します。
getDetailedDisplayMessage()
: 発生したエラーごとにJSFにレポートされるメッセージの詳細部分を、String
オブジェクトまたはHTMLとして戻します。カスタム・エラー・ハンドラで特定の例外をクライアントにレポートする必要がない場合は、null
を戻します。
skipException()
: ユーザー向けに表示される最終的なエラー・リストに、ネストされた例外から各アイテムを表示するかどうかに応じたブール値を戻します。このメソッド・オーバーライドにより、特定の例外タイプをチェックし、ビジネス・シナリオに基づいて、このタイプをリストに表示するかどうかを判断するロジックを実装できます。
例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); }
メッセージの詳細部分をカスタマイズし、使用する予定のある場合は、このメッセージを取得し、処理するために、カスタム・エラー・ハンドラを作成し、getDetailedDisplayMessage
メソッドを実装することができます。最終的なメッセージは、ビュー・レイヤーに渡され、他のメッセージと統合されます。
メッセージの詳細部分をカスタマイズするには:
デフォルトのDCErrorHandlerImpl
クラスを拡張するカスタム・エラー・ハンドラを作成します。
このクラスで、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); } }
DCErrorMessage
インタフェースを実装するカスタム・クラスを作成します。このクラスはgetHTMLText
メソッドおよびgetText
メソッドを実装する必要があります。
getHTMLText
メソッドに、実際の処理を実行するためのコードを追加しますが、インタフェースの要件を満たすには、getText
の実装も必要です。
getHTMLText
の実装では、エラー・メッセージを作成、処理するためのコードを追加します。
getDetailedDisplayMessage
のgetHTMLText
は、エラー・メッセージの最終版を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>
Oracle ADFでは、作成されるBindingContext
オブジェクトごとにカスタム・エラー・ハンドラのインスタンスを1つ作成します。Oracle ADFでは、同じ論理エンド・ユーザー・セッションからの同時Webリクエストをシリアライズするため、通常、複数スレッドは同じエラー・ハンドラを同時に使用しません。しかし、スレッドセーフのカスタム・エラー・ハンドラを保証するには、JboException
でsetProperty()
APIを使用します。このメソッドは、表示用に例外がJSF FacesMessage
オブジェクトに変換されるときに、後で必要になる可能性があるヒントをすべて例外オブジェクト自体に格納します。