| Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド 11gリリース1(11.1.1.9.0) B52029-12 |
|
![]() 前 |
![]() 次 |
この章では、ADF Facesコンポーネントに対してリアルタイムのデータ更新を行うための、非同期バックエンドの登録方法を説明します。
この章では、次の項目について説明します。
Fusionテクノロジ・スタックには、アクティブ・データ・サービス(ADS)が含まれ、これはサーバー側のプッシュ・フレームワークで、これによりADF Facesコンポーネントのリアルタイムのデータ更新を提供できます。ADF Facesコンポーネントをデータ・ソースにバインドすると、ADSでは、ブラウザ・クライアントに明示的な更新リクエストを要求することなく、ブラウザ・クライアントにデータ更新をプッシュします。たとえば、ADFデータ・コントロールの属性にバインドされた表があり、その属性値はサーバー上で定期的に変化するため、表には更新された値が表示されるようにします。ユーザーはJava Beanを作成してActiveModelインタフェースを実装し、それをイベント・リスナーとして登録すると、コンポーネントにバックエンドからのデータ・イベントを通知できます。そのコンポーネントは図37-1に示されるように、新しい値が強調表示された変更済データを再レンダリングします。
ADSの使用は、自動部分ページ・レンダリング(PPR)の使用にかわる方法で、ADF FacesコンポーネントにバインドされたADFデータ・コントロールに関連付けられているビジネス・ロジックの結果として、バックエンドで変化するデータを再レンダリングします。自動PPRではサーバーにリクエストを送信する必要があるのに対し(通常はユーザーによって開始される)、ADSでは、サーバーにデータが到着すると、変更されたデータがデータ・ストアからプッシュされるようにします。また、PPRに対して、ADSでは、コンポーネントによりコンポーネント全体ではなく、変更されたデータのみを再レンダリングするようにできます。これにより、アプリケーションが定期的に変化するデータに対処する必要があるという場合には、ADSは理想的です。
この機能を使用するには、ADSを使用するようにアプリケーションを構成する必要があります。アプリケーション・サービスでADSがサポートされていない場合、ソースのデータが更新されたらコンポーネントでそれを表示できるように、サービスのプロキシを作成する必要もあります。
どのADF FacesページでもADSを使用できます。ただし、アクティブ・データを処理するように構成できるのは、次のADF FacesコンポーネントおよびADFデータ視覚化(DVT)コンポーネントのみです。
activeImage
activeOutputText
pivotTable
tree
treeTable
geoMap (mapPointThemeのみ)
sunburst
treemap
DVTコンポーネントに対するADSサポートの詳細は、23.3.3項「アクティブ・データ・サポート」を参照してください。
また、コレクションベースのコンポーネント(table、tree、pivotTableなど)は、outputTextコンポーネントまたはsparkChartがアクティブ・データを表示するように構成されている場合にのみADSをサポートします。その他のコンポーネントは、コレクションベース・コンポーネントの内部でサポートされません。
アクティブ・データ・サービス・フレームワークと重要な構成情報の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』を参照してください。
ADSを使用するために、必要に応じてアプリケーションを構成して、データ転送の方法やその他のパフォーマンス・オプションを決定することができます。
始める前に:
次のタスクを実行します。
アクティブ・データ・イベントをデータ・ソースから非同期で起動するロジックを実装します。たとえば、このロジックは、データベースを更新するビジネス・プロセスや、JMSから通知されるJMSクライアントです。
アクティブ・データ・フレームワークでは複雑なビジネス・ロジック、またはユーザー・プロファイルやセキュリティなどのADFランタイム・コンテキストが必要な変換はサポートしません。たとえば、フレームワークではADFコンテキスト・ロケール依存の値を変換し、ロケール固有の値を返すことはできません。かわりに、データ変更イベントを発行する前に、データ・ソースにこれを処理させる必要があります。
ユーザーがADF Facesページをアプリケーション用に構成されたADSで実行できるようになるには、その前にWebブラウザのポップアップ・ブロッカを無効にする必要があります。ポップアップ・ブロッカが有効になっているWebブラウザでは、アクティブ・データはサポートされません。
アクティブ・データ・サービスを使用する手順:
必要に応じて、データ転送モードを決定し、待機しきい値や再接続情報など、その他の構成も設定するようにADSを構成します。ADSの構成はadf-config.xmlファイルで行われます。
ADSの構成の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』を参照してください。
オプションで、サーブレットのパラメータを構成し、ユーザーの非アクティブによりタイムアウトとなるまでのアクティブ・セッションの継続時間を指定します。クライアント側のサーブレットのタイムアウト・パラメータの構成は、web.xmlファイルで行われる。
サーブレットのタイムアウト・パラメータ構成の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』を参照してください。
ActiveModelインタフェースを実装し、バックエンドからのアクティブ・データ・イベントのリスナーとして登録するバッキングBeanを作成します。
イベント・オブジェクトをADSフレームワークに渡すようにBaseActiveDataModel APIを拡張するクラスを作成します。
バックエンドからのデータ変更イベントのデータ変更リスナーを登録します。
Webページで、プッシュされたデータを取得し表示するためのADFコンポーネントを実装するマネージドBeanを指定する式を追加して、プッシュされたデータを取得し表示するADF Facesコンポーネントを構成します。
プロパティとしてアクティブ・モデル実装を含むバッキングBeanを作成します。このクラスでは、JSFモデルをラップするのにADSデコレータ・クラスを使用します。このクラスでは、データをADSフレームワークにプッシュするバックエンドからのコールバックも実装されます。
次のADSデコレータ・クラスのいずれかをサブクラスとして持つJavaクラスを作成する必要があります。
ActiveCollectionModelDecoratorクラス
ActiveDataModelDecoratorクラス(グラフと使用)
ActiveGeoMapDataModelDecoratorクラス
ActiveGaugeDataModelDecoratorクラス
これらのクラスは、アクティブ・データ機能をActiveDataModelのデフォルトの実装に委任するラッパー・クラスです。ActiveDataModelクラスは、データ変更イベントをリスニングし、イベント・マネージャと対話します。
特に、ActiveModelインタフェースを実装するときには、次のことを完了します。
JSFモデル・インタフェースをラップします。たとえば、ActiveCollectionModelDecoratorクラスでCollectionModelクラスをラップします。
データ・ソースからのデータ変更イベントに基づいて、アクティブ・データ・イベントを生成します。
ActiveModelインタフェースを実装するには、データの送信先に対してモデルを取得し、それ自体をアクティブ・データ・ソースのリスナーとして登録するJavaクラスに、メソッドを実装する必要があります(例37-1を参照)。
コンポーネントに適したデコレータ・クラスを拡張するJavaクラスを作成します。
例37-1に、ActiveCollectionModelDecoratorを拡張するStockManagerクラスを示します。このクラスでは、データがADF Faces tableコンポーネント用に表示されます。
ActiveDataModelクラスを返すデコレータ・クラスのメソッドを実装し、スカラー・モデルを返すメソッドを実装します。
例37-1に、既存の非同期バックエンドに登録するgetCollectionModel()メソッドの実装を示しています。メッソッドにより、バックエンドから在庫コレクションのリストが返されます。
アクティブ・モデル上でデータを挿入または更新するために使用できるアプリケーション固有のイベントを作成するメソッドを実装します。
例37-1に示すバックエンドからのonStockUpdate()コールバック・メソッドでは、アクティブ・モデル(ActiveStockModelのインスタンス)を使用して、データをADF FacesコンポーネントにプッシュするActiveDataUpdateEventオブジェクトを作成します。
例37-1 デコレータ・クラスの拡張
package sample.oracle.ads;
import java.util.List;
import sample.backend.IBackendListener;
import sample.bean.StockBean;
import sample.oracle.model.ActiveStockModel;
import oracle.adf.view.rich.event.ActiveDataEntry;
import oracle.adf.view.rich.event.ActiveDataUpdateEvent;
import oracle.adf.view.rich.model.ActiveCollectionModelDecorator;
import oracle.adf.view.rich.model.ActiveDataModel;
import oracle.adfinternal.view.faces.activedata.ActiveDataEventUtil;
import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.SortableModel;
// 1. This example wraps the existing collection model in the page and implements
// the ActiveDataModel interface to enable ADS for the page.
public StockManager extends ActiveCollectionModelDecorator implements
IBackendListener
{
// 2. Implement methods from ADF ActiveCollectionModelDecorator class to
// return the model.
@Override
public ActiveDataModel getActiveDataModel()
{
return stockModel;
}
@Override
protected CollectionModel getCollectionModel()
{
if(collectionModel == null)
{
// connect to a backend system to get a Collection
List<StockBean> stocks = FacesUtil.loadBackEnd().getStocks();
// make the collection become a (Trinidad) CollectionModel
collectionModel = new SortableModel(stocks);
}
return collectionModel;
}
// 3. Implement a callback method to create active data events and deliver to
// the ADS framework.
/**
* Callback from the backend to push new data to our decorator.
* The decorator itself notifies the ADS system that there was a data change.
*
* @param key the rowKey of the updated Stock
* @param updatedStock the updated stock object
*/
@Override
public void onStockUpdate(Integer rowKey, StockBean stock)
{
ActiveStockModel asm = getActiveStockModel();
// start the preparation for the ADS update
asm.prepareDataChange();
// Create an ADS event, using an _internal_ util.
// This class is not part of the API
ActiveDataUpdateEvent event = ActiveDataEventUtil.buildActiveDataUpdateEvent(
ActiveDataEntry.ChangeType.UPDATE, // type
asm.getCurrentChangeCount(), // changeCount
new Object[] {rowKey}, // rowKey
null, //insertKey, null as we don't insert stuff
new String[] {"value"}, // attribute/property name that changes
new Object[] { stock.getValue()} // the payload for the above attribute
);
// Deliver the new Event object to the ADS framework
asm.notifyDataChange(event);
}
/**
* Typesafe caller for getActiveDataModel()
* @return
*/
protected ActiveStockModel getActiveStockModel()
{
return (ActiveStockModel) getActiveDataModel();
}
// properties
private CollectionModel collectionModel; // see getCollectionModel()...
private ActiveStockModel stockModel = new ActiveStockModel();
}
クラスをマネージドBeanとしてfaces-config.xmlファイルに登録します。例37-2では、StockManagerBeanの登録を示しています。マネージドBeanを定義することにより、ADF Facesコンポーネントの値プロパティの式でそのマネージドBeanを指定できます。
例37-2 マネージドBeanとして登録
...
<managed-bean>
<managed-bean-name>stockManager</managed-bean-name>
<managed-bean-class>
oracle.afdemo.view.feature.rich.StockManager
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
アクティブ・データを使用するということは、コンポーネントに2つのデータ・ソース(アクティブ・データ・フィードと標準データ・フェッチ)があることを意味します。このため、アプリケーションでは読取り一貫性が確保されるようにする必要があります。
たとえば、ページに表が含まれ、その表でアクティブ・データが有効になっているとします。表には、データを更新する2つの配信方法(通常の表データ・フェッチとアクティブ・データ・プッシュ)があります。たとえば、バックエンド・データがfooからbar、fredに変わるとします。これらの変更ごとに、アクティブ・データ・イベントが起動されます。イベントがブラウザに到達する前に表がリフレッシュされると、標準データ・フェッチにより常に最新データが取得されるため、表にはfredと表示されます。しかしその場合、アクティブ・データ・イベントにはさらに時間がかかるため、リフレッシュ後にデータ変更イベントによりfooがブラウザに着信し、表では表示が一時期fredのかわりにfooに更新されることになります。したがって、読取り一貫性を維持する方法を実装する必要があるのです。
読取り一貫性を実現するために、ActiveDataModelには、データのタイムスタンプを効果的に記録する変更カウントの概念があります。データ・フェッチとアクティブ・データ・プッシュのどちらも、このchangeCountオブジェクトを単調にカウントを増やすことで維持する必要があるため、返されたデータのchangeCountが現在のカウントより低い場合は、アクティブ・イベントにより廃棄される可能性があります。例37-3は、ActiveDataModelクラスの実装を使用して、読取り一貫性を維持する方法を示しています。
マネージドBeanで作成されたイベントを渡すために、BaseActiveDataModelクラスを拡張するクラスを作成する必要があります。ActiveDataModelクラスは、データ変更イベントをリスニングし、イベント・マネージャと対話します。具体的には、実装するメソッドで次のことを行います。
必要に応じて、アクティブ・データおよびActiveDataModelオブジェクトを開始および停止し、データ・ソースに対するリスナーの登録および登録取消しを行います。
イベント・マネージャからリスナーを管理し、アクティブ・データ・イベントをイベント・マネージャにプッシュします。
例37-3に、オブジェクトをfireActiveDataUpdate()メソッドに入れることで、モデルのnotifyDataChange()メソッドでEventオブジェクトをADSフレームワークに渡す方法を示します。
例37-3 ADSへのEventオブジェクト渡し
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import oracle.adf.view.rich.activedata.BaseActiveDataModel;
import oracle.adf.view.rich.event.ActiveDataUpdateEvent;
public class ActiveStockModel extends BaseActiveDataModel
{
// -------------- API from BaseActiveDataModel ----------
@Override
protected void startActiveData(Collection<Object> rowKeys,
int startChangeCount)
{
/* We don't do anything here as there is no need for it in this example.
* You could use a listenerCount to see if the maximum allowed listerners
* are already attached. You could register listeners here.
*/
}
@Override
protected void stopActiveData(Collection<Object> rowKeys)
{
// same as above... no need to disconnect here
}
@Override
public int getCurrentChangeCount()
{
return changeCounter.get();
}
// -------------- Custom API -----------
/**
* Increment the change counter.
*/
public void prepareDataChange()
{
changeCounter.incrementAndGet();
}
/**
* Deliver an ActiveDataUpdateEvent object to the ADS framework.
*
* @param event the ActiveDataUpdateEvent object
*/
public void notifyDataChange(ActiveDataUpdateEvent event)
{
// Delegate to internal fireActiveDataUpdate() method.
fireActiveDataUpdate(event);
}
// properties
private final AtomicInteger changeCounter = new AtomicInteger();
}
バックエンドからのデータ変更イベントに対するデータ変更リスナーを登録する必要があります。例37-4では、リスナーBeanStockBackEndSystemがfaces-config.xmlファイルに登録されます。この例では、リスナーをバックエンドに挿入するために式言語が使用されています。
例37-4 データ更新イベント・リスナーの登録
...
<managed-bean>
<managed-bean-name>backend</managed-bean-name>
<managed-bean-class>
oracle.afdemo.backend.StockBackEndSystem
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>listener</property-name>
<value>#{stockManager}</value>
</managed-property>
</managed-bean>
コレクションベースのデータを表示するADFコンポーネントは、ADSを使用するように構成でき、ビュー・レイヤーで特別な設定は必要ありません。リスナーを登録すると、ADSを使用してデータをビュー・レイヤーに流すことができます。たとえば、JSPXページでtableコンポーネントを使用して、リスナーを登録しているバックエンド・ソースからの在庫の更新を表示するとします。
例37-5に、プッシュされたデータを受信するためにtable コンポーネントのvalue属性で使用される式言語を示します。
例37-5 アクティブ・データの表示
...
<f:view>
<af:document id="d1">
<af:form id="f1">
<af:panelStretchLayout topHeight="50px" id="psl1">
<f:facet name="top">
<af:outputText value="Oracle ADF Faces goes Push!" id="ot1"/>
</f:facet>
<f:facet name="center">
<!-- id="af_twocol_left_full_header_splitandstretched" -->
<af:decorativeBox theme="dark" id="db2">
<f:facet name="center">
<af:panelSplitter orientation="horizontal"
splitterPosition="100" id="ps1">
<f:facet name="first">
<af:outputText value="Some content here." id="menu"/>
</f:facet>
<f:facet name="second">
<af:decorativeBox theme="medium" id="db1">
<f:facet name="center">
<af:table value="#{stockManager}" var="row"
rowBandingInterval="0"
id="table1" emptyText="No data...">
<af:column sortable="false" headerText="Name"
id="column1">
<af:outputText value="#{row.name}" id="outputText1"/>
</af:column>
<af:column sortable="false"
headerText="Value...." id="column2">
<af:outputText value="#{row.value}"
id="outputText2" />
</af:column>
</af:table>
</f:facet>
</af:decorativeBox>
</f:facet>
</af:panelSplitter>
</f:facet>
</af:decorativeBox>
</f:facet>
</af:panelStretchLayout>
</af:form>
</af:document>
</f:view>