複数のブラウザー・ページ用の Web アプリケーションの設計

タブ・サポートのない従来型 Web ブラウザーの場合、ブラウザー・インスタンスにそれぞれ単一ページがあります。各ブラウザー・ページは、Web サーバーで実行中の Web アプリケーションに接続されている間は、それぞれ独自のセッション・オブジェクトに関連付けられています。この場合、セッションに保管されたクライアントとサーバーの会話状態 (コンテキスト・データ) は、単一ページに属しています。セッションの属性とリソースに加えて、これにはステートフル・セッション Bean も含まれています。
複数のタブおよびウィンドウがある Web ブラウザーでは、同じ Web アプリケーションに接続するすべてのページは、同じセッション・オブジェクトとセッション Bean を共有します。このため、サーバーは、すべてのページの記録を保持し、各ページのコンテキスト・データを個別に保管する必要があります。一般的に、マルチ・ページ・サポートに対する要求を扱う場合、Web アプリケーションは、ページ ID を使用して、セッションまたはその他の使用可能なストレージ域からのコンテキスト・データにアクセスする必要があります。Managed Bean にも特別な注意が必要です。各ページの現在の状態にアクセスするために、ステートフル・セッション Bean はページ ID を使用する必要があります。
しかし、セッションことに 1 つのページを処理するように設計された Web アプリケーションは、複数のページ ID を自動的にサポートすることはありません。 JViews でページ ID 機能を有効にすると、複数のタブまたはページをもつブラウザー・インスタンスを扱う Web アプリケーションを設計して実行することができます。

JViews ページ ID を有効にする

JViews ページ ID 機能は、デフォルトでは、無効になっています。JViews ページ ID は、web.xml ファイルでコンテキスト・パラメーター ilog.views.faces.PAGEID_SUPPORT を true に設定すれば有効になります。
<context-param>
   <param-name>ilog.views.faces.PAGEID_SUPPORT</param-name>
   <param-value>true</param-value>
</context-param>
true 以外の値の場合、この機能は無効になります。

サーバー・サイドでのマルチ・ページ・サポート

有効になった JViews ページ ID 機能は、IlvServletPageIdUtil.PAGE_ID パラメーター (jviewsPageId) に対する要求をチェックして、Web アプリケーションにアクセスするすべてのページを自動的に検出し、記録します。こうした要求が見つからない場合、JViews は、要求を新規ページからのものとみなし、その新規 ID を作成します。
ここで Web アプリケーションがページ ID をチェックして、コンテキスト・データ (データ・ファイルとデータ・ソース、選択状態、IlvManagerView インスタンスなど) を作成して、保管する必要があります。
JSF アプリケーションでページ ID を取得するために、以下の公開 API メソッドが使用可能です。
  • IlvFacesPageIdUtil.getPageId() は、現行要求に関連したページ ID を返します。 ID が存在しなければ、新規に作成されます。ページ ID が必要な場合、必ずこのメソッドを呼び出す必要があります。
  • IlvFacesPageIdUtil.setSessionAttributeWithPageId(String,Object) は、指定のユーザー・キーに現行ページ ID を追加してセッションの属性を保管します。セッションでページ固有データ (コンテキスト・データ) を保管するときには、このメソッドを呼び出す必要があります。
  • IlvFacesPageIdUtil.getSessionAttributeWithPageId(String) は、ユーザー・キーと現行ページ ID に基づいてセッションから属性を取得します。セッションからページ固有データ (コンテキスト・データ) を取得するときには、このメソッドを呼び出す必要があります。
非 JSF ページでページ ID を取得するために、以下の公開 API メソッドが使用可能です。
  • IlvServletPageIdUtil.getPageId(HttpServletRequest) は、指定の HTTP 要求からのページ ID を返します。ID が存在しなければ、新規に作成されます。ページ ID が必要な場合、必ずこのメソッドを呼び出す必要があります。
  • IlvServletPageIdUtil.setSessionAttributeWithPageId(HttpServletRequest,String,Object) は、指定のユーザー・キーに現行ページ ID を追加して指定の HTTP 要求に関連したセッションの属性を保管します。 セッションでページ固有データ (コンテキスト・データ) を保管するときには、このメソッドを呼び出す必要があります。
  • IlvServletPageIdUtil.getSessionAttributeWithPageId(HttpServletRequest,String) は、ユーザー・キーと現行ページ ID に基づいて、指定の HTTP 要求に関連したセッションから属性を取得します。セッションからページ固有データ (コンテキスト・データ) を取得するときには、このメソッドを呼び出す必要があります。
これらの API メソッドは、JViews ページ ID 機能へのアクセスを可能にし、ブラウザー・ページに固有に割り当てられているセッション属性を保管および取得するための手段を提供します。

クライアント・サイドでのマルチ・ページ・サポート

ページ ID は、クライアント・サイドで保管され、すべての HTTP 要求のパラメーター (jviewsPageId) としてサーバーに対して実行依頼されます。
JViews JavaScript ライブラリーは、クライアント・サイドでページ ID にアクセスするために以下の API メソッドを提供します。
  • IlvPageId.instance.getPageId() は、ページ ID を返します。クライアント・サイドでページ ID が必要な場合、必ずこのメソッドを呼び出す必要があります。
通常このメソッドは不要ですが、サーバーに HTTP 要求を実行依頼する JavaScript ルーチンを Web アプリケーションが実装する場合は、その要求にページ ID を含む jviewsPageId パラメーターが含まれるようにする必要があります。実行依頼時には、追加のフォーム・タグからの要求にもこのパラメーターが含まれる必要があります。
タグ・ライブラリーを使用した JViews Maps コンポーネントの宣言
次の MapView コンポーネント宣言について考えてみましょう。
<h:form id="form">
  <jvmf:mapView id="mapId" 
     style="width:500px;height:300px"
     data="/data/map.ivl" />
</h:form>
上記の例では、MapView コンポーネントは、どの Managed Bean にも関連していません。このシナリオでは、JViews は、ページ・コンテキスト・データ (IlvManagerView および map.ivl データ・ファイル) を自動的に保管します。このように宣言されている場合の JViews Maps JSF コンポーネントは、複数のブラウザー・ページを自動的にサポートします。
Managed Bean と MapView データ属性との関連付け
次の例では、MapViewdata タグ属性を dataBean Bean の dataSource プロパティーと関連付けます。
<h:form id="form">
  <jvmf:mapView id="mapId" 
     style="width:500px;height:300px"
     data="#{dataBean.project}" />
</h:form>
この場合、JViews は、ページ ID に従って対応する IlvManagerView インスタンスを自動的に保管しますが、Managed Bean (dataBean) が project プロパティーに対して同じことを行うようにする必要があります。 このことは、次のように、これを、セッションからプロジェクトを作成または取得する要求 Bean に変換すれば可能になります。
  // Holds the map project in the request bean
  private String mapProject = null;

  // The constructor tries to fetch the map project from the session, 
  // creating a new one if needed
  public DataBean() {
    // Try to retrieve the map project from the session
    mapProject = (String)IlvFacesPageIdUtil.getSessionAttributeWithPageId("mapProjectId");
    if (null == mapProject) {
      // Map project not found in session, create a new one and then store it
      mapProject = createMapProject();
      IlvFacesPageIdUtil.setSessionAttributeWithPageId("mapProjectId", mapProject);
    }
  }

  // The getter just returns the map project reference
  public String getProject() {
    return mapProject;
  }
コード・スニペットには、getter メソッド (getProject) が IlvFacesPageIdUtil API を使用してマップ・プロジェクト・オブジェクトをセッション・オブジェクトに永続的に保管する場合に考えられる要求 Bean 実装を示しています。IlvFacesPageIdUtil は、ページ ID に基づいて要求の実行依頼元のページを判別します。この例では、data タグ属性について説明していますが、このソリューションは他のタグ属性にも使用できます。
Managed Bean と GoogleView タグとのバインディング
次の例は、GoogleView を Managed Bean にバインドする方法を示します。このシナリオでは、GoogleView インスタンスがブラウザー・ページ単位で正しく保管されるようにする必要があります。
<h:form id="form">
  <jvmf:googleView binding="#{dataBean.view}" 
     id="gMapId" 
     key="#{keyBean.googleKey}"
     level="7"
     style="width: 750px; height: 350px"
 </h:form>
前記の例で説明したように、dataBean Bean は、ページ ID を使用して、セッションから GoogleView インスタンスを取得できる要求 Bean に変換されます。
  // Holds the Google View JSF component in the request bean
  private IlvFacesGoogleViewComponent googleView = null;

  // The constructor tries to fetch the Google View JSF component 
  // from the session, creating a new one if needed
  public DataBean() {
    // Try to retrieve the Google View JSF component from the session
    googleView = (IlvFacesGoogleViewComponent)IlvFacesPageIdUtil.getSessionAttributeWithPageId("viewId");
    if (null == googleView) {
      // Google View JSF component not found in session, 
      // create a new one and then store it
      googleView = new IlvFacesGoogleViewComponent();
      IlvFacesPageIdUtil.setSessionAttributeWithPageId("viewId", googleView);
    }
  }

  // The getter just returns the component reference
  public IlvFacesGoogleViewComponent getView() {
    return googleView;
  }

  // The setter can be ignored because the bean relies on the session
  // to retrieve the component
  public void setView(IlvFacesGoogleViewComponent googleView) {
    // does nothing
  }