編集者注: この記事は、2001年11月に発表されたDavid Lection氏のWebSphere Portal Serverバージョン1.2および2.1 に関する記事の最新版です。本稿は最新の後継製品であるWebSphere Portalバージョン4.1について説明しています。
ポータルとポータル・サーバーは、今日、インターネットおよびWeb開発で最も注目を浴びている技術です。Webサイトの開発に携わる人であれば誰でも、何らかのポータル・テクノロジーを使用しています。
なぜこんなにポータル・テクノロジーがもてはやされるのでしょうか。MS-DOSの時代を思い出してみましょう。MS-DOS時代には、PCは1度に1つのアプリケーションを実行していました。別のアプリケーションに切り替えたいときには、DOSプロンプトでまず1つのアプリケーションを閉じてから、新しいアプリケーションの名前を入力しなくてはなりませんでした。それぞれのアプリケーションがPC画面全体を占有し、コンピューターのリソースをすべて使用していました。
その後、MicrosoftがWindowsを発表しました。Windowsでは、各アプリケーションがそれぞれ固有のウィンドウに表示されるため、生産性の向上が期待できました。複数のアプリケーションを実行するとともに、実行中のアプリケーションをクリックするだけで、アプリケーション間の切り替えができるようになりました。Windowsはオペレーティング・システムとして、多くの面で、最先端のコンピューティングを前進させました。最もよく知られている拡張機能の1つに、ウィンドウを使用したユーザー・インターフェースがあります。Windowsは、互いに重なり合うウィンドウ状の長方形を使用して、複数のアプリケーションの表示を一度に集約することができました。アプリケーションの集約 こそがポータル・サーバーの主要な機能です。
そして、一気に ワールド・ワイド・ウェブ (WWW) の誕生へと進化します。Webの登場という情報化時代の大きな進歩があった一方で、Webを表示するツールはまだ設計初期段階に留まっていました。当時のブラウザーの一般的な設計は、ある意味では、1980年代のMS-DOSと同様でした。つまり、URLを入力し、Webサイトを1つだけ表示するというものでした。
Webとその関連のブラウザーの進化にともなって、ユーザーがデータの集合を表示できるようにするいくつかの方式が登場しました。すなわち、Java、Javaアプレット、およびその他のタイプのプラグイン・インターフェースのサポートを提供するブラウザーの登場です。これらのブラウザーは、他の情報チャネル (主に音声および映像情報) を提供する際によく用いられました。
これらのアプレットやプラグイン・インターフェースは、使用可能なブラウザー間で標準化されることがなかったため、すべての一般的なWebブラウザーで適切に動作するWebページを構築しようとしているWeb専門のプログラマーにとっては、まさに悪夢のような状態でした。
一方で、Webサイトにサービスを提供するWebサーバーは独自の方法で進化していました。これらのサーバーは、最初のうちは、Webサイトを構成するきわめて静的なコンテンツを提供するだけでした。しかし、これらは急速に進化して、現在ではおなじみのアプリケーション・サーバーになりました。これらのアプリケーション・サーバーでは、動的なコンテンツが提供できます。静的なページは、サーブレットおよびJavaServer Pages (JSP) コンポーネントに取って代わられました。
ポータルのサポートは、アプリケーション・サーバーから発展し、複数のストリームの動的なコンテンツを集約して、それをユーザーに提示したいという願望から生まれたものです。初期段階のポータルは、特定のWebサイトをサポートするために特別に作成されたカスタム・アプリケーションでした (YahooおよびeBayがカスタムビルトのポータルの良い例です)。
これらのポータルが進化するにつれて、カスタマーが自分自身のポータルを構築できるようにするシステムやフレームワークが登場してきました。Epicentric PortalおよびPlumtree Corporate Portalが、カスタマーによるビジネス固有のポータルの作成を可能にするポータル・サーバー製品の例です。これらのポータルはカスタマーに2つの機能を提供しています。すなわち、統一的で斬新 (ざんしん) な方法でコンテンツを集約するサーバー、およびポータルと拡張機能を構築するフレームワークです。
ポータルのアプリケーション構成要素であるポートレットは、多くの点でWindowsアプリケーションに酷似しています。Windowsアプリケーションは、ウィンドウにそのデータを表示します。ポートレットもまた、ウィンドウに似たディスプレイにそのデータを表示します。Windowsアプリケーションのタイトル・バーには、ユーザーがアプリケーションを拡大 (最大化) したり縮小 (最小化) したりできるコントロールがあります。ポートレットもタイトル・バーを持っており、同様のコントロールがあります。以下のWindowsアプリケーションのサンプルとそれに似たポートレットを見てみると、それぞれのアプリケーションのユーザー・インターフェースに複数の類似点があることが分かります。
図1. サンプルWindowsアプリケーション
図2. サンプル・ポートレット・アプリケーション
ポートレットは、以前のWindowsアプリケーションと同様に、オペレーティング・システムと協調して動作する必要があります。不安定でパフォーマンスが劣るWindowsアプリケーションは、システム全体に影響を与えます。そして、このことは、十分に開発されていないポートレットにも当てはまります。
昨年、IBMはWebSphere Portal Serverを発表しました。これは、ポータル・ベースのWebサイトの作成と管理をサポートします。WebSphere Portalを使用することで、企業間 (B2B)、企業-従業員間 (B2E)、および企業-消費者間 (B2C) の最良のポータルの構築が可能になります。
2002年4月、IBMはWebSphere Portalバージョン4.1を発表しました。このIBMの主要ポータル・サーバーの最新版からの提供物により、ポータル・サーバーの機能、パフォーマンス、およびスケーラビリティーのレベルが向上します。バージョン4.1は、次のような多くの新しい機能および能力をサポートしています。
- J2EEに準拠
- Webサービス・ベースのポートレットのサポート
- 強力で新しいページ・カスタマイザー
- ページ・グループ
- ポータルの新規のルック・アンド・フィール (さらに多くの選択可能なテーマやスキンなど)
- ポートレットAPI機能拡張
これらはWebSphere Portalバージョン4.1の新規拡張の一部を示したにすぎません。このリリースについての詳細は、参考文献を参照してください。
WebSphere Portalバージョン4.1ポートレット・プログラミングAPIは、ポートレットとポータル・アプリケーションの開発のための、高度で堅固な次世代のフレームワークを提供します。このフレームワークは、J2EE Javaプログラミング標準をベースにしており、次のような、ポートレットの開発のために作成された優れた機能セットを提供します。
- ポートレット・マークアップ・レンダリング
- イベント処理
- シングル・サインオン
- ポートレット・メタデータ・ストレージ
- ユーザー・プロファイル
- クライアント・デバイス機能
現在のWebSphere Portalは、J2EE準拠のアプリケーションです。このことが意味する最も重要な点は、ポートレットがそのJavaの継承をJ2EEサーブレット・クラスから受けるということです。これはポートレットにとっては吉報です。サーブレット・クラスで使用可能な機能やフィーチャーが、たいていの場合、ポートレットでも使用できるようになるためです。
ポートレット・プログラミングの世界に初めて足を踏み入れるユーザーのために、以下の例では、WebSphere Portalをセットアップおよび使用して、独自のポートレットを開発する方法を示しています。
ポートレットを開発するには、まず、ポートレット開発環境と実行時環境をセットアップする必要があります。これらの環境は1台のマシンにセットアップ可能ですが、パフォーマンスの向上を図るために2台のマシンを使用することもできます。
2台のマシンを使用したセットアップでは、1台目のマシンはポートレット開発マシンとなり、ここにJava開発ツールとWeb開発ツールをインストールします。これらのツールは、ポートレットのさまざまなコンポーネントの開発に使用します。Java Development Kit (JDK) のレベルをアプリケーション・サーバーのレベルと同じにすることをお勧めします。WebSphere Portalバージョン4.1では、JDK 1.3.1を使用するWebSphere Application Serverバージョン4.02が必要になります。
開発マシン用のツールをインストールすると、WebSphere Portalバージョン4.1に付属しているPortal Toolkitを試してみたいと思うでしょう。Portal Toolkitは、WebSphere Studio Application Developerにプラグイン可能で、完全なポートレット開発環境を提供するツールとサンプルのパッケージ・セットです。Application DeveloperとPortal Toolkitを使用することで、新規ポートレットを簡単に開発できます。このツールキットには、幾つかのサンプル・ポートレットとポートレット開発ウィザードが含まれています。このウィザードは、完全なテンプレート・ポートレットを作成することにより、Javaコード、JSPページ、およびXML配置記述子などのポートレット・アプリケーションの開発を高速化します。(今後の記事で、Portal Toolkitについてさらに詳しく紹介します。また、ツールキットとそれに関連するソフトウェア・コンポーネントのインストールに関するチュートリアルも掲載する予定です。)
もう1つのマシンはポータル実行時マシンです。このマシンには、WebSphere Application Server 4.02をインストールして、最新のパッチ・セットを適用する必要があります。WebSphere Portalの実動バージョンをインストールする予定の場合は、IBM DB2 Universal Databaseバージョン7.1およびIBM Secureway Directoryバージョン3.2もインストールする必要があります。WebSphere Portalの完全リリース用のこれらの前提製品は、ポータル・パッケージに含まれています。
実行時マシンの用途が、作成したポートレットのテストだけの場合、デベロッパー・バージョンのポータルをインストールできます。バージョン4.1のポータル・サーバーには、WebSphere Application Server、DB2、およびデベロッパー・バージョンのポータルのインストールが必要になります。
両方のマシンにソフトウェアをインストールして、そのテストを実行したら、ポートレットの開発に必要な以下のJavaアーカイブ (JAR) ファイルへの参照を、開発マシンのCLASSPATHに追加する必要があります。
- portlet-api.jar
- wpsportlets.jar
- j2ee.jar
- wps.jar
- jlog-2.2.jar
注: ご使用のポートレット・アプリケーションによっては、他のJARファイルが必要になる場合があります。この記事の例では、ここに示したJARファイルのみが必要となります。
これらのJARファイルを開発マシンで使用する最も簡単な方法は、実行時マシンからネットワークを経由して、開発マシンにあるこれらのファイルを参照することです。ポータル・インストール・ディレクトリー内のこれらのJARファイルの正確な場所については、WebSphere Portalの資料 (参考文献を参照) をご覧下さい。
これで完全な開発環境が整いましたので、ポートレットのプログラミングをいくつか実践してみましょう。
新しいプログラミング手法および言語への導入の標準的な方法は、Hello Worldアプリケーションから始めることです。これはポートレット・プログラミングを開始する簡単な方法であり、HelloWorldポートレットを使用して、開発マシンおよび実行時マシンのセットアップを検証することができます。
HelloWorldポートレット
//********************************************************************
//*
//* HelloWorld.java - Example Portlet #1 Shows simple portlet structure
//*
//********************************************************************
package com.ibm.wp.samples.helloworld;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloWorld extends PortletAdapter
{
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
public void service( PortletRequest portletRequest,
PortletResponse portletResponse )
throws PortletException, IOException
{
PrintWriter writer = portletResponse.getWriter();
writer.println("<p>Hello Portal! This is my first Portlet!</p>");
}
}
|
HelloWorldは高度な機能を備えていないものの、ポートレットの基本構造を示しています。単純なポートレットは単一のメソッドであるserviceメソッドを必要とします。ポートレットのserviceメソッドは、ポータルがポートレットにそのデータの表示を要求したときに呼び出されます。このサンプルでは、データは以下のようなマークアップです。
<p>Hello Portal! This is my first Portlet!</p> |
ポートレット、ポートレット・アプリケーション、およびポートレット・アプリケーション記述子
ポートレット はマークアップを生成し、ポータル・ページの長方形の領域に表示されます。関連するポートレットの集合はポートレット・アプリケーションを構成し、Webアーカイブ (WAR) ファイル に一緒にパッケージされます。単一のWARファイルにパッケージされた複数のポートレットは、イメージ、スタイルシート、JSPコンポーネント、および他のタイプのリソースを共用できます。WARファイルは、Webアプリケーション配置記述子と呼ばれる特殊なXML記述子を含む、特別に構成されたJARファイルです。XML記述子のファイル名はweb.xmlです。このファイルは、常にWARファイルの "web-inf" ディレクトリーに保管されます。
ポートレット・アプリケーションのWARファイル内のweb.xmlファイルの他に、ポートレット・アプリケーションと関連ポートレットを含むWARファイルには、ポートレット・アプリケーション記述子も入っていなければなりません。ポートレット・アプリケーション記述子のファイル名はportlet.xmlであり、このファイルも常にWARファイルの "web-inf" ディレクトリーに保管されます。
HelloWorld Webアプリケーション記述子: web.xml
HelloWorldのWebアプリケーション記述子
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD
Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app id="WebApp_504848313">
<display-name>Hello World Portlet Application - Portlet
Sample #1</display-name>
<servlet id="Servlet_439329280">
<servlet-name>HelloWorld</servlet-name>
<servlet-class>com.ibm.wp.samples.helloworld.HelloWorld</servlet-class>
</servlet>
<servlet-mapping id="ServletMapping_439329280">
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld/*</url-pattern>
</servlet-mapping>
</web-app>
|
Webアプリケーション記述子は、ポートレット・アプリケーションWARファイル内のポートレットを、サーブレット としてアプリケーション・サーバーに記述します。各ポートレットはサーブレットとして定義され、ポートレット・アプリケーションはWebアプリケーションと同じものを表すことになります。
HelloWorldポートレット・アプリケーション記述子:portlet.xml
HelloWorldのポートレット記述子
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 1.1//EN"
"portlet_1.1.dtd">
<portlet-app-def>
<portlet-app uid="504848313">
<portlet-app-name>Hello World Portlet Application - Portlet
Sample #1</portlet-app-name>
<portlet href="WEB-INF/web.xml#Servlet_439329280"
id="Portlet_439329280">
<portlet-name>HelloWorld</portlet-name>
<cache>
<expires>0</expires>
<shared>no</shared>
</cache>
<allows>
<minimized/>
</allows>
<supports>
<markup name="html">
<view/>
</markup>
</supports>
</portlet>
</portlet-app>
<concrete-portlet-app uid="640682430">
<portlet-app-name>Concrete Hello World Portlet Application -
Portlet Sample #1</portlet-app-name>
<context-param>
<param-name>Portlet Master</param-name>
<param-value>yourid@yourdomain.com</param-value>
</context-param>
<concrete-portlet href="Portlet_439329280">
<portlet-name>HelloWorld</portlet-name>
<default-locale>en</default-locale>
<language locale="en_US">
<title>Hello World - Sample Portlet #1</title>
<title-short>Hello-Worldd</title-short>
<description>Hello World - Sample Portlet #1</description>
<keywords>portlet hello world</keywords>
</language>
</concrete-portlet>
</concrete-portlet-app>
</portlet-app-def>
|
この文書にはポートレット・アプリケーション、アプリケーション内の各ポートレット、および各ポートレットのタイトルと機能が記述されています。これは、きわめて基本的なバージョンのポートレット・アプリケーション記述子とそれに必要なタグです。ここではそれぞれのタグの意味については説明しません。Webアプリケーション記述子とポートレット・アプリケーション記述子の両方の文書の各タグおよび関連するタグ値の詳細な説明は、「WebSphere Portal Guide to Portlet Programming」(参考文献を参照) を参照してください。
ここまでで、ポートレットのソース・コードおよびXML記述子文書の準備ができたので、次に、このアプリケーション・コンポーネントを作成して、WARファイルにパッケージします。ソース・コード、Web記述子文書、およびポートレット記述子文書を、ポートレットとWARファイルを容易に作成できるようなディレクトリー構造に配置します。例えば、以下のようなディレクトリー構造です。
HelloWorldポートレットのディレクトリー構造
d:/HelloWorld
d:/HelloWorld/WEB-INF/web.xml
d:/HelloWorld/WEB-INF/portlet.xml
d:/HelloWorld/WEB-INF/classes/com/ibm/wp/samples/helloworld/HelloWorld.java
|
このディレクトリー構造を使用して、ポートレットをコンパイルし、関連したWARファイルを作成するバッチ・ファイルを作成できます。このバッチ・ファイルでは、JDK CLASSPATHがこのポートレットのコンパイルに必要なポータルJARファイルを指すようにセットアップされていることが前提となります。この例では、このバッチ・ファイルにBuildEx1.batという名前を付け、HelloWorldディレクトリーに入れました。バッチ・ファイルの2行目を変更して、以下に示すように、必ずポートレット・ファイルを保管したベース・ディレクトリーを指すようにしてください。
以下の例 (および後続の例) では、表示上の都合で、幾つかの行が分割されているので注意してください。
バッチ・ファイルbuildex1.bat
echo off
set bd=D:/HelloWorld
javac -d
%bd%/WEB-INF/classes
%bd%/WEB-INF/classes/com/ibm/wp/samples/helloworld/HelloWorld.java
jar cvf0 HelloWorld.war WEB-INF
|
このバッチ・ファイルを実行すると、ポートレットがコンパイルされて、WARファイルが作成されます。これでポートレット・アプリケーションが正常に作成できたので、このポートレット・アプリケーションを実行時ポータル・マシンで実行してみることにしましょう。
ポートレットをインストールしてそれをテストするには、ポータルにログインする必要があります。ご使用のブラウザーのアドレス・フィールドにポータルのURLを入力すると、ポータルが表示されます。ポータルは汎用ホーム・ページを開いて表示します。ポータルにログインするためにログイン・アイコン (
) をクリックして、次に、管理者としてログインする必要があります。以下はWebSphere Portalに含まれている標準のポータル・ホーム・ページの表示例です。
図3. ポータル・ホーム・ページの例
ポータルにログインした後、「ポータル管理 (Portal Administration)」ページ・グループを選択し、「ポートレット管理 (Portlet Administration)」ページを表示します。この例では、「ポートレットのインストール (Install Portlets)」ページを使用して、HelloWorldポートレット・アプリケーションをインストールします。ポートレットWARファイルを、ポータル・サーバー・マシンからアクセス可能なディレクトリーにコピーする必要があります。「インストール (Install)」をクリックして、ポートレットをインストールします。ポートレットのインストールの完了に際し、一連の画面および確認が表示されます。
ポートレットをインストールしたら、ポータル・ページ・カスタマイザーを使用して、ポートレットをポータル・ページに追加する必要があります。カスタマイザーは、ポータル・ページへのポートレットの追加や調整を可能にするポータルのアプリケーションです。ページ・カスタマイザーを使用するには、「ページの作業 (Work with Pages)」ページ・グループに変更し、「レイアウトとコンテンツの編集 (Edit Layout and Content)」タブを選択する必要があります。そして、ページ・カスタマイザーが表示されます。
ここでは分かりやすくするために、ポートレットを「ウェルカム (Welcome)」ページに追加します。このページは、ページの「ホーム (Home)」ページ・グループにグループ化されています。カスタマイザー・ページの上部で、変更するページ・グループとページを選択します。「ホーム (Home)」ページ・グループと「ウェルカム (Welcome)」ページが選択されていることを確認してください。
「ポートレットの取得 (get portlets)」リンクをクリックして、ページに追加するポートレットのリストを取得します。ポートレットのリストからHelloWorldを選択し、「ジャンプ (Go)」を押します。HelloWorldがカスタマイザーのポートレット・リストに戻されます。ポートレットを選択し、カスタマイザーの左上の列で「ポートレットの追加 (Add portlet)」アイコンをクリックします。これで、ポートレットがページの左側の列に追加されます。
ページのカスタマイズが完了したら、ページをアクティブにする必要があります。
図4. WebSphere Portalページ・カスタマイザー
ページを表示すると、ポートレットとおなじみの "Hello Portal World" というフレーズが表示されます。
図5. HelloWorldポートレットのスクリーン・ショット
HelloWorldはポートレット・プログラミングの優れた入門ですが、ポートレット開発のイメージをより鮮明にするためには、さらに幾つかのポートレットの概念を紹介する必要があります。
ポートレットおよびJavaServer Page (JSP)
ポータル・アグリゲーターがデータを表示させるためにポートレットを呼び出すと、ポートレットは、マークアップのストリームを送り出し、そのマークアップをポートレット応答オブジェクトを介して使用可能なプリント・ライターに入れることにより応答します。これは、ポートレットの観点からは単純なインプリメントである反面、ポートレットのユーザー・インターフェースがより複雑になるにつれて難しくなります。ここで必要とされるのが、ポートレットが表示 (レンダリング) を別のエンティティーに委任するためのメソッドです。WebSphere Portalでは、このエンティティーはJSPコンポーネントになります。
WebSphere PortalポートレットAPIは、JSPコンポーネントを使用してポートレットのマークアップを表示するための優れたサポートを提供します。実際に、ポートレットとサーブレットは実行時リンケージを使用して、データをJSPコンポーネントに渡します。
ポートレットは、特定のJSPコンポーネントに渡されるデータを含むJava Beanを作成します。ポートレットは、このBeanへの参照をポートレット要求内におきます。次に、ポートレットはポートレット・コンテキスト・メソッドのinclude() を呼び出して、コンポーネントを起動します。JSPコンポーネントはuseBean タグを使用してBeanへの参照を設定し、必要に応じてBeanからデータを抽出して、Beanのデータを適切なマークアップと結合します。次に、コンポーネントは、このマークアップを出力ストリームに直接送り出します。ポートレット・アグリゲーターは、その結果を他のポートレットの他のマークアップと結合し、ポータル・ページを生成します。
ポートレットは、Java Beanへの参照をポートレット要求オブジェクトではなく、ポートレット・セッション・オブジェクトに保管することもできます。これらのBeanはより長いライフサイクルを持っており、通常、明示的に削除されるか、ポータル・セッションが終了するまで有効です。セッションに入れられたBeanは、複数のマシンがクラスター内に配置されたアプリケーション・サーバー構成では、オーバーヘッドが高くなります。Beanはシリアライズし、クラスター内の各マシンにコピーして、すべてのクラスター・マシン間でポータル・セッション状態を保持するようにする必要があります。
以下のHelloAgainポートレット・サンプルは、BeanとJSPコンポーネントを使用して、パーソナライズされたハロー・メッセージを表示しています。
HelloAgainポートレット・クラス
//******************************************************************
//*
//* HelloAgain - A sample portlet that uses a JSP for rendering
//*
//******************************************************************
package com.ibm.wp.samples.helloagain;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import java.io.*;
public class HelloAgain extends PortletAdapter
{
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
protected static final String jsp = "/WEB-INF/html/HelloAgain.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
// Make a bean
HelloAgainBean hab = new HelloAgainBean();
// Get the portlet context
PortletContext context = getPortletConfig().getContext();
// Get portal user object
User user = request.getUser();
// get user's full name
String userName = user.getFullName();
// A valid name returned?
if( userName == null )
{
userName = "Unknown WebSphere Portal User";
}
// Save name in bean
hab.setUserName( userName );
// Save bean in request
request.setAttribute( "HelloAgainBean", hab );
// Invoke the JSP to render
context.include(jsp, request, response);
}
}
|
上記のポートレット・コードでの最初のなすべきことは、JSPに渡されるBeanの作成です。Beanが作成されると、ユーザー名がポータル・ユーザー・オブジェクトから取得され、Beanにコピーされます。Beanへの参照がポートレット要求に置かれ、JSPを呼び出してポートレットのマークアップを表示するために、ポートレット・コンテキストのincludeメソッドが呼び出されます。
以下に示すように、関連するJava Beanには単一のJava String属性があります。
HelloAgain Java Bean
//********************************************************************
//*
//* HelloAgainBean.java - The bean used to pass data to the display
//* JSP in the HelloAgain portlet application
//*
//********************************************************************
package com.ibm.wp.samples.helloagain;
import java.util.*;
public class HelloAgainBean
{
private String userName = ";
public void setUserName(String s)
{
userName = s;
}
public String getUserName()
{
return( userName );
}
}
|
以下の例では、JSPコンポーネントはBeanへの参照を設定し、ユーザー名の値を出力マークアップに組み込みます。
HelloAgain表示コンポーネント
<!---------------------------------------------------------------------->
<!-- -->
<!-- HelloAgain,jsp - A sample JSP used to render data from a portlet -->
<!-- -->
<!---------------------------------------------------------------------->
<%@ page contentType="text/html" errorPage=" %>
<jsp:useBean id="HelloAgainBean"
class="com.ibm.wp.samples.helloagain.HelloAgainBean" scope="request" />
<h1>Hello Again <%=HelloAgainBean.getUserName()%></h1>
<br><h2>This is markup rendered from a JSP</h2>
|
例には、サンプルを作成するためのバッチ・ファイルが含まれています。作成プロセスはHelloWorldポートレットと同じです。ポートレットが正常に作成できたら、それをポータルにインストールして実行します。以下のような出力が得られます。
図6. HelloAgainポートレットのスクリーン・ショット
最後のサンプルのWorldTimeには、提示された概念がすべて取り入れられています。この例では、ユーザーの居住地の時刻を表示します。ポートレットには、ユーザーの時刻とグリニッジ標準時 (GMT) との時差とユーザーの居住地名を入力するカスタマイズ・ページがあります。ポートレットが最大化されると、24のそれぞれの時間帯にある都市の時刻が表示されます。また、ポートレットには、ポートレットのカスタマイズ方法を説明するヘルプ・ページもあります。
このサンプルでは4つの新しいポートレットの概念が紹介されています。これらの新しい概念は、上の2つの例で示したJSPコンポーネントとポートレット構造の使用という概念とともに、ご使用のアプリケーションの強力なポートレットを構築するために必要な概念です。
ポートレットがコンテンツを表示するために呼び出されると、そのポートレットには、ポートレット要求オブジェクトのモード標識が渡されます。以下のポートレット・モードが使用可能です。
- 表示 (View) モード
これはポートレットのデフォルト・モードです。ポートレットがこのモードのときは、ポートレットはデフォルトの表示モードでデータを表示します。
- 編集 (Edit) モード
このモードは、ユーザーがポートレットのタイトル・バーに表示される編集アイコン
を押したときにアクティブになります。ポートレットが編集モードの場合、ユーザーがポートレットの設定をカスタマイズできるダイアログが表示されます。 - 構成 (Configure) モード
ポータルの管理者は、ポートレット管理プロセス時に、「パラメーターの変更 (Modify Parameters)」機能を選択してポートレットの構成を呼び出すことができます。このモードのポートレットには、管理者がポータルのポートレットを構成できるダイアログが表示されます。この設定は、グローバルな性質を有し、通常はポートレット (例えば、ターゲットのバックエンド・サーバーのURLなど) 用の設定であり、特定のユーザー用の設定ではありません。
- ヘルプ (Help) モード
このモードは、ユーザーがポートレットのタイトル・バーに表示されるヘルプ・アイコン
を押したときにアクティブになります。ポートレットがヘルプ・モードの場合、ヘルプ情報がユーザーに表示されます。このヘルプ情報では、ポートレット設定のカスタマイズ方法とポートレット表示の解釈の仕方について説明します。
ポートレットは、このモード値を確認して適切なマークアップを表示し、所要のユーザー・インターフェースを作成する必要があります。通常、ポートレットは、それぞれのモードごとにJSPコンポーネントとJava Beanを作成し、関連するポートレット・モードの表示が要求されたときに、このBeanとJSPを呼び出すことによりこの作業を行います。
ポートレットはまた、ユーザーがポートレットを最大化しているかどうかを判別するために、そのウィンドウ状態の検査が必要な場合があります。ポートレットのタイトル・バーに表示される最大化アイコン
をクリックすると、ポートレットが最大化されます。ポートレットが最大化されると、ページ上の他のすべてのポートレットは隠れた状態になります。これにより、ポートレットは最大サイズの画面領域を使用してそのコンテンツを表示します。
最大化が可能なポートレットは、通常、最大化表示のための特殊なJSPコンポーネントを持っています。このJSPコンポーネントは、追加の画面領域を利用して、さらに多くのコンテンツ、あるいはコンテンツの詳細をユーザーに表示します。
これまでの説明は、ユーザーに対するコンテンツの表示に限定されていました。通常、ポートレットは、単にコンテンツをユーザーに表示する以上の働きをします。すなわち、ポートレットは、ユーザーがさまざまな方法でコンテンツと対話することを可能にするユーザー・インターフェース・メタフォーも提供します。多くのポートレットは、フォームを使用してそのユーザー・インターフェースを表示します。フォームは、入力データ・フィールドと各種ボタン (ラジオ・ボタン、チェック・ボックス、およびプッシュボタンなど) から構成できます。
以下のJavaコードの断片は、WorldTimeポートレットのコア・クラスです。serviceメソッドとactionPerformed メソッドで行われるプロセスについては、後で詳しく説明します。
WorldTimeポートレット・クラス
//******************************************************************
//*
//* WorldTime.java - A sample portlet that uses a JSP for rendering
//*
//******************************************************************
package com.ibm.wp.samples.worldtime;
import org.apache.jetspeed.portlet.DefaultPortletAction;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
import org.apache.jetspeed.portlet.event.*;
import java.io.*;
public class WorldTime extends AbstractPortlet implements ActionListener
{
public void init(PortletConfig portletConfig) throws
UnavailableException
{
super.init( portletConfig );
}
public final static String homeCity
= "HomeCity"; // Field and Persistence
public final static String timeOffset
= "TimeOffset"; // Names
public final static String portletSaveAction
= "save"; // Save action
public final static String unspecifiedCityValue
= "Unspecified City"; // Unspecified city
protected static final String jspNormalView
= "/WEB-INF/html/WorldTimeNormalView.jsp";
protected static final String jspMaxView
= "/WEB-INF/html/WorldTimeMaxView.jsp";
protected static final String jspEditView
= "/WEB-INF/html/WorldTimeEditView.jsp";
protected static final String jspHelpView
= "/WEB-INF/html/WorldTimeHelpView.jsp";
public void service( PortletRequest request, PortletResponse response)
throws PortletException, IOException
{
String jsp = null;
// View Mode?
if( request.getMode() == Portlet.Mode.VIEW )
{
// Make a bean
WorldTimeBean wtb = new WorldTimeBean();
String homeCity = null;
String timeOffset = null;
// Get Data Store Reference
PortletData pData = request.getData();
homeCity = (String) pData.getAttribute(WorldTime.homeCity);
timeOffset = (String) pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null & homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null & timeOffset.length() > 0)
? timeOffset : "0") );
// Save bean in request
request.setAttribute( "WorldTimeBean", wtb );
// Is window maximized?
if( (request.getWindow()).getWindowState() ==
PortletWindow.State.MAXIMIZED )
{
// Maximized View JSP
jsp = jspMaxView;
}
else
{
// Normal view JSP
jsp = jspNormalView;
}
}
// Edit mode?
else if( request.getMode() == Portlet.Mode.EDIT )
{
// Make a bean
WorldTimeBean wtb = new WorldTimeBean();
String homeCity = null;
String timeOffset = null;
// Get Data Store Reference
PortletData pData = request.getData();
homeCity = (String) pData.getAttribute(WorldTime.homeCity);
timeOffset = (String) pData.getAttribute(WorldTime.timeOffset);
wtb.setHomeCity( ((homeCity != null & homeCity.length() > 0)
? homeCity : unspecifiedCityValue) );
wtb.setTimeOffset( ((timeOffset != null & timeOffset.length() > 0)
? timeOffset : "0") );
// Create a save URI encoded with a save action
PortletURI saveURI = response.createReturnURI();
DefaultPortletAction action = new
DefaultPortletAction( WorldTime.portletSaveAction );
saveURI.addAction(action);
// Save the URI in the bean
wtb.setSaveURI(saveURI.toString());
// Create a cancel URI and save in the bean
PortletURI cancelURI = response.createReturnURI();
wtb.setCancelURI(cancelURI.toString());
// Save bean in request
request.setAttribute( "WorldTimeBean", wtb );
// Point at edit JSP
jsp = jspEditView;
}
else if( request.getMode() == Portlet.Mode.HELP )
{
jsp = jspHelpView;
}
// delegate rendering to JSP
(getPortletConfig().getContext()).include( jsp, request, response );
}
// Portlet's action handler
public void actionPerformed(ActionEvent event)
{
PortletLog pLog = getPortletLog();
System.out.println( "WorldTimeActionListener: Event" );
System.out.println( "WorldTimeActionListener: Event
type:("+event.getAction()+")" );
DefaultPortletAction action = (DefaultPortletAction) event.getAction();
if( (action != null) &
(action.getName().equalsIgnoreCase(WorldTime.portletSaveAction)) )
{
PortletRequest request = event.getRequest();
System.out.println( "WorldTimeActionListener: Action Event" );
try // Attempt retrieval and save of portlet form data
{
PortletData pData = request.getData();
String homeCityValue = request.getParameter( WorldTime.homeCity );
String timeOffsetValue = request.getParameter( WorldTime.timeOffset );
if( (homeCityValue != null) & (homeCityValue.length() > 0) )
{
homeCityValue = homeCityValue.trim();
}
else
{
homeCityValue = WorldTime.unspecifiedCityValue;
}
if( (timeOffsetValue != null) & (timeOffsetValue.length() > 0) )
{
timeOffsetValue = timeOffsetValue.trim();
}
else
{
timeOffsetValue = "0";
}
pData.setAttribute( WorldTime.homeCity, homeCityValue );
pData.setAttribute( WorldTime.timeOffset, timeOffsetValue );
pData.store();
}
catch( AccessDeniedException ade )
{
pLog.error( "WorldTime: Java AccessDeniedException Exception ( " + ade
+ " ) thrown when saving instance data to the portlet store");
}
catch( java.io.IOException e )
{
pLog.error( "WorldTime: Java I/O Exception ( "+ e
+ " ) thrown when saving instance data to the portlet store");
}
}
}
}
|
このポートレットのserviceメソッドは、ポートレット・モードおよびウィンドウ状態のテストのために高度化されています。表示および編集のポートレット・モードの場合、Beanは適切なJSPコンポーネントに渡されます。通常の表示モードでは、ユーザーの時刻と居住地が表示されます。最大化表示モードでは、各都市とその現地時間のリストが表示されます。ポートレットのカスタマイズ・モード (コードでは編集モード) では、ユーザーは自分の居住地および居住地の時刻とグリニッジ標準時 (GMT) との時差を入力します。
編集モードでは、2つのURIが作成されます。これらのURIは、JSPコンポーネントに渡されて、表示フォームの「保管 (save)」ボタンおよび「取り消し (cancel)」ボタンに割り当てられます。これらのURIはエンコードされており、ユーザーがこれらのいずれかのボタンを押すと、ポータルがURIをデコードして、どのポートレットがボタン・イベントを生成したかを判別し、そのイベントによりポートレット・イベント・ハンドラーを呼び出すことができるようになっています。
JSPコンポーネントが決定されると (さらに、Beanを必要とするポートレット表示モードの場合は、Beanが作成されてデータがロードされると)、制御がコンポーネントに渡されて、ポートレットのユーザー・インターフェースが表示されます。
以下の画面は、幾つかのポートレット表示モードとウィンドウ・サイズを示しています。
図7. WorldTime通常ビュー
図8. WorldTime最大化ビュー
図9. WorldTime編集ビュー
図10. WorldTimeヘルプ・ビュー
すべてのポートレット・モードがポータル・ページ内に表示されることに注意してください。ただし、ポートレットのヘルプ・モードは例外です。ポートレットのヘルプが呼び出された場合、ヘルプは別のブラウザー・ウィンドウに表示されます。
ユーザーがこれらのいずれかのユーザー・インターフェース・コントロールと対話し、コントロールによりhttp submit イベントが生成されてアプリケーション・サーバーに送られると、http flow がポータル・サーバーに返されます。ポータル・サーバーは、どのポートレットがイベントを生成したかを判別し、そのイベントをアクション・イベントとしてポートレットに送達します。
アクション・ハンドラーを組み込むのはポートレットの責任です。このアクション・ハンドラーは、ポートレットがイベントを処理する必要があるときに呼び出されます。WorldTimeポートレット・クラスには、アクション・イベントを処理するためのactionPerformedメソッドが組み込まれています。以前のバージョンのポートレットAPIでは、アクション・ハンドラーは別のJavaクラスに保管されました。WebSphere Portalバージョン4.1およびポートレットAPI 1.1では、アクション・ハンドラー (およびその他の組み込みポートレット・イベント・ハンドラー) は、ポートレット・クラス内に直接インプリメントされます。
ここでのアクション・ハンドラーは、ある特定のイベントのテストを行います。ここでのハンドラーは、保管アクションを処理するためにインプリメントされます。保管アクションは、ユーザーがポートレットのカスタマイズ・ページで「保管 (Save)」をクリックすると生成されます。
上記イベント・ハンドラーの主要な機能は、ユーザーがポートレット・カスタマイズ・ページに入力したデータを取得することです。フォーム上の各フィールドからデータを取得して、それをポートレットのデータ・ストアに保管し、後で表示するためにこのデータを使用できるようにする必要があります。名前で定義されているJSPコンポーネントのフィールドは、ポートレット要求のパラメーターとしてイベント・ハンドラーで使用でき、getParameter() メソッドを使用して取得されます。続いて、データ値は、ポートレット・データ・オブジェクトのデータ項目ごとにsetAttribute を呼び出して、ユーザー用のポートレット・データ・ストアに名前で保管されます。ポートレット・データ・オブジェクトのstoreメソッドを呼び出すと、データ値は永続ストレージにコミットされます。
次はWorldTimeポートレットで使用されるJSPコンポーネントのソースとなるものです。
以下のクラスは、ポートレットの表示モードおよび編集モードでJSPに渡されたBeanのインプリメンテーションです。このBeanは、任意の時間帯の時刻を計算し、フォーマット設定します。また、Beanには、ユーザーの居住地、ユーザーの居住地の時刻とグリニッジ標準時との時差、およびカスタマイズ・ページの「保管 (Save)」ボタンと「取り消し (Cancel)」ボタンを表示するためのイベント・ハンドラーURLが含まれています。
World Time Java Beanクラス
//********************************************************************
//*
//* WorldTimeBean.java - A sample Java bean that passes data from a
//* portlet to a JSP for markup rendering
//*
//********************************************************************
package com.ibm.wp.samples.worldtime;
import java.util.*;
import java.text.*;
public class WorldTimeBean
{
private String homeCity = WorldTime.unspecifiedCityValue;
private int timeOffset = 0;
private String saveURI = ";
private String cancelURI = ";
public void setSaveURI(String s)
{
saveURI = s;
}
public String getSaveURI()
{
return( saveURI );
}
public void setCancelURI(String s)
{
cancelURI = s;
}
public String getCancelURI()
{
return( cancelURI );
}
public void setHomeCity(String s)
{
homeCity = s;
}
public String getHomeCity()
{
return( homeCity );
}
public String getHomeTime()
{
return( getLocalTime(timeOffset) );
}
public String getLocalTime( int localTimeOffset )
{
GregorianCalendar now = new GregorianCalendar();
int realTimeOffset = (-timeOffset) + localTimeOffset;
now.add( Calendar.HOUR_OF_DAY, realTimeOffset );
Date timeNow = now.getTime();
String localTime =
DateFormat.getTimeInstance(DateFormat.SHORT).format(timeNow);
return( localTime );
}
public void setTimeOffset( String inTimeOffset )
{
try
{
timeOffset = (int) Integer.parseInt( inTimeOffset );
}
catch( Exception e )
{
timeOffset = 0;
}
}
public String getTimeOffset()
{
return( Integer.toString(timeOffset) );
}
}
|
本稿は、ポートレット・プログラミングの可能性の一端を紹介したにすぎません。ここでは、ポートレットの開発環境および実行時環境の設定方法など、ポートレット・プログラミングを開始する際の方法を説明しました。また、HelloWorldポートレットを使用して、基本中の基本となるポートレットを紹介し、ポートレットの構造、およびポータル・サーバー上でポートレットを作成、パッケージ、および配置する方法についての概要を説明しました。また、ポートレットのモード、ポートレットのウィンドウ状態、JSPコンポーネントおよびJava Beansを使用したポートレット内のデータ表示、およびポートレットのイベント処理について、それぞれの概念を紹介しました。
これらの概念により、ポートレット・プログラミングの基本がお分かりいただけたことと思います。これらの概念をご使用のアプリケーションの既存のデータ・コネクターと結合することにより、強力なポートレットを構築することができ、読者の製品を最新のインターネット・ポータルで活用することができます。
今後の記事では、ポートレット・プログラミングについて、ポートレット・メッセージング、ポートレット・パフォーマンス、およびPortal Toolkitの紹介とチュートリアルなどのトピックについて説明します。
| ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|
| i-portalv4.zip | 17.4KB | HTTP |
- この記事で説明したサンプル・コードのZIPファイルをダウンロードしてください。
-
WebSphere Portal製品のサイト(日本語サイト)をご覧ください。ここに、インフォセンターが含まれています。
-
ポートレット・カタログからポートレットをダウンロードしてください。
-
パーベイシブ・コンピューティングのポータル・サイトを参照し、ポータル・アプリケーションのモバイル化の方法を習得してください。
- WebSphere Portal 4.1についてのさらに詳しく知りたい場合は、WebSphere Portal 4.1: Functionality and integration aspects (WebSphere、2002年8月) で、WebSphere Portal Enable、WebSphere Portal Extend、およびWebSphere Portal Experienceのコンポーネントの概要を学んでください。PDF形式のこの白書には、コンポーネントの機能についての詳細も表形式で掲載されています。
- WebSphere Portal Serverのポートレットの開発については、このチュートリアルをご覧ください。
- IBMレッド・ブックAccess Integration Pattern using IBM WebSphere Portal で詳細な情報を入手してください。
- IBMのコースのWebSphere Portalのインプリメント (現在はWebSphere Portalバージョン2.1についての説明) にご参加ください。
