|
|||||||||||||||||||||||||||||||||||
WebSphere Portal V5.1.0.1プログラミング・モデルを活用する:第2部:高度なURL生成ポータル・ナビゲーション制御の実装 |
|||||||||||||||||||||||||||||||||||
|
Stefan Behl (stefan.behl@de.ibm.com),Software Engineer,IBM Stefan Hepper (sthepper@de.ibm.com),WebSphere Portal Programming Model Architect,IBM Stefan Koch (stefkoch@de.ibm.com),Software Engineer,IBM Carsten Leue (CLEUE@de.ibm.com),WebSphere Portal Runtime Architect, IBM レベル:初級 原文の掲載:2006年03月08日 更新日:2006年09月01日更新
はじめにモノリシックなWebアプリケーションを作成する開発者は、アプリケーション内のすべてのアスペクトを完全に制御できます。アプリケーション開発者は、必要に応じてURLを自由に設計できます。しかし、ポータル環境では事情が異なります。ポータル・アプリケーション開発者は、他のコンポーネントと結合されて1つの大きなポータル・アプリケーションに組み込まれるコンポーネントを提供します。このため、独自の方法でURLを生成することはできず、開発者はポータル・フレームワークによって提供されるメカニズムに従ってURLを作成する必要があります。WebSphere Portalでは、マークアップを生成する(このため、URLの作成機能を必要とする)主要コンポーネントは次のとおりです。
この記事では、Java APIを使用したテーマとスキンのURLの生成方法を説明します。テーマとスキンのURLは、ポータルJSPタグ・ライブラリー(リソース・リストの「WebSphere Portal Information Center, Portal tag library」セクションを参照)のURLタグとURLGenerationタグを使用しても作成できます。これらのタグはほとんどのユース・ケースをカバーするため、一般的なユース・ケースではこれらのタグを使用してください。ただし、Java APIまたは追加機能が必要な状況では、Navigational State SPIと呼ばれるWebSphere Portal V5.1.0.1 System Programming Interface(SPI)を使用することができます。このようなユース・ケースの1つとして、URLを使用して別のテーマのテンプレートに切り替える場合が挙げられます。 他のポートレットを指すURLを生成する必要があるポートレットは、ポートレットAPIを使用しなければなりません(詳細については、リソース・リストの「JSR 168 Portlet Specification」リンクを参照してください)。たとえば、ポートレットAが別のページにあるポートレットBにパラメーターを送信し、ユーザーをそのページに移動させるユース・ケースを考えます。この場合、ポートレットBを指すURLを作成してページ階層をポートレットAにハード・コーディングする代わりに、ポートレットAでプロパティー・ブローカーのインフラストラクチャーを使用し、イベントを発生させる必要があります。ポータル管理者は、ポートレットAのイベントをポートレットBの入力に結び付けます。この結果、ポータルはそのページへの切り替えを自動的に実行します。詳細については、「リソース」の『Developing JSR 168 compliant cooperative portlets』を参照してください。 この記事は、ポータルの基本概念(第1部参照)とJSPの基礎を理解し、Javaプログラミングに習熟していることを前提として書かれています。
ステート・ハンドリングの確認WebSphere Portal V5.1は、ポートレットについてのJSR168ナビゲーション・ステートの概念をポータル・サーバーのステートに拡張します。JSR168モデルは、ポートレットが使用できるステートとして、次のタイプのステートをサポートします。
図1.WebSphere Portalのさまざまなステート ![]() ポートレットを設計するときは、ポートレットが管理するステートを識別し、これらを適切にエンコードする必要があります。特に、ナビゲーション・ステートとセッション・ステートはお互いに直交するよう設計しなければなりません。異なるナビゲーション・ステートと組み合わせて、同じセッションにアクセスできるからです。一般に、これが発生するのは、ユーザーが「戻る」ボタンを使用するとき、ポートレット特有のステートが含まれるブックマークを呼び出すとき、またはオリジナルのウィンドウとセッションを共有する新しいブラウザー・ウィンドウを開き、双方のウィンドウを個別にナビゲートするときなどです。 ポートレットによって生成された各リンクは、次の2つのカテゴリーに分類されます。
ポートレットの概念と同様に、テーマとスキンもアクション/レンダー・リンクのセマンティクスを持つリンクを生成します。これは、ポートレット・ステートではなく、ポータル・ステートの変更に関連します。
ナビゲーション・ステートのエンコードナビゲーション・ステートは、特定のクライアントに関連するポータルのビューを表します。クライアントはWebページと対話することにより(たとえば、新しいページへの移動により)、異なるビューを要求(照会)することができます。このタイプの対話はサーバー上の何も変更せず、サーバーによって提供される新しいビューだけを要求します。このため、これはHTTP用語でいう「安全な」オペレーションです。この対話は、ユーザーが最新のビュー間を前後に移動できる特性を持ちます。また、ビューをブックマークしておき、後でブラウザーのブックマークを呼び出すことにより、そのビューに戻ることができます。開発者は、WebSphere Portalのナビゲーション・ステートをURLにエンコードすることで、この動作を実装します。異なるナビゲーション・ステートからは、異なるURLが生成されます。
Navigational State SPIを調べる次に、新しいNavigational State SPIの主な概念と、これらの概念がお互いにどのように関連するのかを見ていきましょう。また、アクセサー・アプリケーション・プログラミング・インターフェース(Accessor Application Programming Interface)についても解説します。これは、ナビゲーション・ステート情報へのタイプ付きアクセスを可能にする便利なインターフェースです。次のセクションで説明するすべてのインターフェースとクラスは、 com.ibm.portal.state.* にパッケージングされています。
ナビゲーション・ステートとURLを表すWebSphere Portal Version 5.1から、ナビゲーション・ステートは、ステート情報の階層として表されます。オブジェクト・モデルはタイプなしのステート情報を含むDOMに似た文書モデルで、java.lang.Stringとして表されます。この設計の決定は、「一般的なポータル・ページは多数のURLを含み、1つの要求につきナビゲーション・ステートが複数回シリアライズされる必要がある」という前提に基づいています。ストリング・ベースのメモリー表現によって、ナビゲーション・ステートのURLへの効率的なシリアライズが可能になります。つまり、シリアライズ・プロセスの際に、時間とCPUを消費する、オブジェクトからストリングへの変換を避けられます。しかし、プログラマーの観点からは、厳密にタイプ付けされたインターフェースを使用してステート情報にアクセスする方がより便利でフェイルセーフとなります。このため、ステート・ハンドリングAPIには、ナビゲーション・ステート情報へのタイプ付きの読み取りおよび書き込みアクセスを提供する使いやすいインターフェース(アクセサーAPIの一部)が含まれています。「アクセサーAPIを使用したナビゲーション・ステートの読み取りと書き込み」を参照してください。 新しいステート・ハンドリングSPIの設計では、一般的なパターンとして、読み取り専用インターフェースを、読み取りおよび書き込み可能インターフェース(コントローラー)から分離する方法が使用されています。このため、APIはナビゲーション・ステートへの次の2つのインターフェースを提供します。
図2では、ステート・ホルダーが、タイプなしの文書モデルを内包するラッパーであることが示されています。このような設計となっているのは、まず、現在のナビゲーション・ステートを複製し、その後で、生成されたURLの特定のセマンティクスに従ってナビゲーション・ステートを変更する必要があるためです。たとえば、プログラマーが特定のポータル・ページを指すURLを作成したいとき、ステート文書モデル内のページ選択情報を変更しなければなりません。しかし、ページ上のすべてのURLでこの変更を有効にすべきではありません。 図2.タイプなしのDocumentModelを内包するStateHolder ![]() ステート・ホルダーのライフタイムは1つの要求が処理されるまでの間です。要求を処理するときに、ステート・ホルダーが通過するライフサイクルのフェーズを図3に示します。
図3.StateHolderオブジェクトのライフタイム ![]() URLはcom.ibm.portal.state.EngineURLインターフェースによってモデル化されます。EngineURLはナビゲーション・ステートを含むURLを表します(「URLエンコードを理解する」を参照)。適切なURLファクトリーから新しいEngineURLインスタンスを要求するときに、EngineURLが参照する初期ステート・ホルダーを指定します。通常、これは要求固有のベース・ステートのコピーです。 APIの中心的なオブジェクトであるEngineURLインターフェースの簡単な概要をリスト1に示します。最も重要なメソッドは、この特定のEngineURLインスタンスが参照するステート・ホルダー・オブジェクトを返すgetState()メソッドです。このメソッドは変更可能なインターフェース(StateHolderController)をステート・ホルダーに返すため、プログラマーはこのEngineURL用にステートを変更できます。ステートの変更方法の詳細については、「アクセサーAPIを使用したナビゲーション・ステートの読み取りと書き込み」を参照してください。 writeCopy()メソッドおよびwriteDispose()メソッドによって、EngineURLを指定されたWriter(たとえば、HTTP応答から取得したマークアップPrintWriter)へストリーミングすることができます。(toString()を使用することもできますが、これはかなりコストの高いオペレーションなので、推奨できません。) リスト1.EngineURLインターフェース
URLエンコードを理解するWebSphere Portal V5.1に導入されたURLエンコードの実装は、次の点でパフォーマンスが最適化されています。
これらの要件を満たすために、URLエンコードはデルタ・エンコードと呼ばれる手法を用いて実装されます。デルタ・エンコードは、プログラマーが明示的に他のステートにURLのベースを置かない限り、固定されたベース・ステート(アクション・フェーズの後で利用可能)を、(少なくとも概念的に)各URLに含める必要があるという考えに基づいています。作成された各URLのベース・ステートがシリアライズされるのを防ぐため、アクション・フェーズの直後に前もってシリアライズ(プレシリアライズ)が行われます。URLの生成時に、プレシリアライズされたベース・ステートは、非相対的な各URLに設定されます。URL固有のセマンティクスを指定するステート・デルタは、相対URLのパス情報に個別にエンコードされます。 次の例は、コーデック識別子 kcxmlの後にシリアライズされたベース・ステート部分を含む絶対「デルタURL」です。デルタ・コーデック識別子delta/base64xmlの直後に、ステート・デルタ部分があります。
相対URLを生成できると、状態はさらに改善されます。ブラウザーは、相対URLを現在の要求URLまたはHTMLベース・タグの値(存在する場合)に追加します。WebSphere Portalは、プレシリアライズされたベース・ステートをHTMLベース・タグを使用してHTMLページのヘッダーに挿入することにより、相対URLを活用します。具体的な相対URLには、ステート・デルタのみが含まれます。次の例は、この規則によってマークアップ・サイズが大幅に削減されることを示します。
相対URLを使用できないケースもあります。たとえば、プロトコルがhttpからhttpsに切り替わる場合は、生成されたURLは絶対URLでなければなりません。また、マークアップでJavaScriptが多用されていると、ブラウザーは相対URLを解決できません。ポータル・ページに含まれるカスタム・マークアップでのこのようなJavaScriptの問題を防ぐために、WebSphere Portal ではデフォルトで相対URLが無効になっています(たとえば、ポートレットによって生成されたマークアップなど)。しかし、Navigational State SPIには、明示的に相対URLを作成する方法が用意されています(詳細については、「URLAccessorFactoryを使用したURLの作成」を参照してください)。
アクセサーAPIを使用したナビゲーション・ステートの読み取りと書き込みアクセサーAPIは、ステート文書モデルへのタイプ付きアクセスを提供します。アクセサーAPIにより、プログラマーは容易にナビゲーション・ステート情報を照会および変更することができます。図4に、アクセサーAPIを示します。アクセサーAPIは、特定のノードへのアクセスを階層的な文書モデルにカプセル化する抽象化層です。ナビゲーション・ステートの各様相について(たとえば、ページ選択、展開ステート、ポートレット・ステートなど)、アクセサーAPIはアクセサー・ファクトリーを提供します。アクセサー・ファクトリーは、参照する特定のステートに応じた読み取り専用アクセサーと読み取りおよび書き込みアクセサーを提供します。アクセサーは、ステート文書モデルの対応する位置から、直接読み取りや書き込みを行います。また、アクセサーは必要な型変換も行います。 必要なナビゲーション・ステート情報はステート文書モデル内にあり、専用のアクセサー・ファクトリー・インプリメンテーション内にカプセル化されています。一般に、アクセサー・ファクトリーはパス表記を使用して、ステート文書モデル内で特定の文書ノードを検索したり、ノード(または、ノードの完全なパス)を作成します。ノードが見つかると、アクセサー・ファクトリーは、ノード参照をアクセサーまたはアクセサー・コントロールに、その初期化中に渡します。アクセサー(およびアクセサー・コントローラー)のインプリメンテーションは、ステート文書モデルの構造から独立しています。つまり、必要な情報がステート文書モデル内の別のノードに移動した場合でも、アクセサーを再使用できます。 図4にいくつかの重要なアクセサーを示します。対応するアクセサー・ファクトリーは省略されています。 図4.アクセサーAPI ![]() それでは、選択アクセサー・ファクトリーcom.ibm.portal.state.selection.SelectionAccessorFactoryと、それに関連するすべてのインターフェースを詳しく見ていきましょう。これらをリスト2に示します。 リスト2.SelectionAccessorFactoryインターフェースと関連インターフェース
他のアクセサー・ファクトリーと同様に、SelectionAccessorFactoryは読み取り専用のSelectionAccessorを返すメソッドと、読み取りおよび書き込み可能なSelectionAccessorControllerを返すメソッドを公開します。getSelectionAccessor()メソッドは、読み取り専用のStateHolderインターフェースを引数として受け取ります。getSelectionController()には、読み取りおよび書き込み可能なStateHolderControllerインターフェースが必要です。 アクセサーが動作するステートは、必ずしも、要求URLから取得された要求固有のベース・ステートではないため、この軽量のパターン(ステートが引数として渡される)が選択されています。通常、これは特定のEngineURL用に作成されたステート・クローンです。EngineURLオブジェクトにgetState()を呼び出すことにより、URL固有のステート・ホルダーを取得できます。SelectionAccessorControllerを使用して、作成されたEngineURLが特定のポータル・ページ(たとえば、[Stock Market]ページ)を指すようにする方法をリスト3に示します。 リスト3.SelectionAccessorControllerを使用したページ・リンクの作成
ベース・アクセサー・インターフェースは、com.ibm.portal.Disposableインターフェースから派生しています。アクセサーが不要になったとき、プログラマーはdispose()メソッドをそのアクセサーに呼び出すことにより、不要なアクセサーを明示的に示すことが推奨されています。これにより、アクセサー・ファクトリー・インプリメンテーションはオブジェクト・プールにアクセサー・ファクトリーを保存し、パフォーマンスを改善することができます(初期化のオーバーヘッドとガーベッジ・コレクションが削減されます)。
PortalStateManagerServiceを使用したURLの生成WebSphere Portalバージョン5.1.0.1の新しいサービスであるPortalStateManagerServiceを使用すると、プログラマーはポータルの高度なユース・ケースを実装するURLを容易に作成できます。このサービスは、次の目的で使用できます。
次のサブセクションでは、PortalStateManagerServiceへのアクセス方法とURLの作成方法を説明します。最後のサブセクションでは、この新しいサービス(SPIの一部)を使用するカスタムのパンくずリスト・ナビゲーション・タグの実装方法を説明します。 PortalStateManagerServiceへのアクセス PortalStateManagerServiceにアクセスするには、名前検索ポータルservice/state/PortalStateManagerでJNDI検索を使用します。検索は、特定のcom.ibm.portal.state.service.PortalStateManagerServiceを取得するgetterメソッドを持つcom.ibm.portal.state.service.PortalStateManagerServiceHomeインターフェースを返します。 PortalStateManagerServiceHomeインスタンスは、ポータルのライフタイムで有効です。このため、JNDI検索は1回だけ実行し、取得したホーム・オブジェクトを保存します(たとえば、インスタンス内または静的変数内に保存します)。 PortalStateManagerHomeオブジェクトとは異なり、PortalStateManagerServiceには要求のスコープがあります。つまり、PortalStateManagerServiceは1つのサーブレット要求でのみ使用できます。それ以降のすべてのサーブレット要求では、ホーム・インターフェースからの新しいサービス・インスタンスを要求する必要があります。このサービスへのアクセス方法をリスト4に示します。 リスト4.PortalStateManagerServiceへのアクセス方法
PortalStateManagerServiceインターフェースは、com.ibm.portal.Disposableインターフェースから派生しています。サービスが不要になったとき、プログラマーはdisposeメソッドを呼び出すことにより、不要なサービスを明示的に示すことが推奨されています。このサービスは要求スコープを持つため、遅くとも要求の最後ではサービスを破棄する必要があります。 サービスの要求スコープの規則に関し、1つだけ例外があります。要求の処理(または、ポータル)から完全に切り離されている環境またはコンポーネントでこのサービスが使用されている場合、サービスのライフタイムは未定です。このような場合、ホーム・インターフェースからサービスを要求し、要求と応答でnullを渡すことにより、適切なときにそれを破棄できます。 PortalStateManagerServiceの使用 com.ibm.portal.state.PortalStateManagerServiceインターフェースには、次の2つのメソッドがあります。
このサービスを使用するには:
次に、URLAccessorFactoryを使用してURLを作成する方法を見ていきましょう。
|
|||||||||||||||||||||||||||||||||||