Shunguo Yan (shunguoy@us.ibm.com ), Advisory Software Engineer, IBM, Intel, Microsoft,HP
レベル:中級
原文の掲載:2007年3月7日
原文はこちら(US)
この記事では、JSR168ポートレット・コンテナー・フレームワークおよびStruts Tilesと統合されたIBMR WebSphereR Application Server Version 6.1(以降、Application Serverと表記)の集約タグを使用して、ポータル・ページを作成する方法を解説します。この記事は、既存のポートレットまたは個別に開発されたJSR 168ポートレットを Webページに迅速に統合し、ポータルのルック・アンド・フィールの実現を望んでいるWebアプリケーション開発者を対象としています。Javaプログラミング、ポートレット、Struts Titleフレームワーク、およびApplication Serverを十分に理解している必要があります。これらのトピックを理解するのに役立つ参考資料については、『リソース 』を参照してください。
はじめに
IBM WebSphere Application Serverは、バージョン6.1以降は、内蔵のJSR168ポートレット・コンテナーを提供しています。これにより、以前はポータル・サーバー(IBM WebSphere Portalなど、以降WebSphere Portalと表記)だけにデプロイできたポートレットを、Application Server V6.1にデプロイできるようになりました。
この機能により、いくつかの大きな利点が得られます。
ポートレットを再利用可能なコンポーネントとして書くことができます。これらのポートレットを最初にApplication Serverで使用し、その後でJSR 168互換ポータル・サーバー(WebSphere Portalなど)で使用して、ポータル・サーバーのより高度な機能を活用できます。
オープン・ソースまたは商用のカタログ(WebSphere Portalカタログなど)から、他の開発者が書いた標準ポートレットをApplication Serverに統合できます。
さまざまなビジネス・ニーズに合わせ、サーブレットとともにポートレットをデプロイすることができます。たとえば、ポートレットを使用してさまざまなデータを集約したビューを提供し、サーブレットを使用して多数のページ・フローをともなう複雑なユーザー・インターフェースを処理することが可能です。
ページ上で小さな長方形の領域を占有するポートレットは、パーベイシブ・デバイスに簡単にレンダリングできます。このため、さまざまな画面サイズを持つパーベイシブ・デバイスに対し、アプリケーションの対応性が高まります。たとえば、アプリケーションの表示方法として、携帯電話では1つのポートレットを画面全体に表示し、ポケットPCでは画面上に2つのポートレットを並べて表示し、Webブラウザーでは複数のポートレットを表示する、といった指定が可能です。
しかし、Application Server 6.1は、拡張機能は備えていません。またポータル・サーバー(WebSphere Portalなど)に通常組み込まれている機能は提供していません。ポータルの最大の特徴は、カスタマイズ可能なルック・アンド・フィールです。通常、ポータル・サーバーでは、カスタマイズとパーソナライゼーションが構成を通じて動的に処理されます。たとえば、ユーザー・グループに基づいて、ページのテーマやスキンを動的にパーソナライズすることができます。またポートレットを使用する特別なユーザー・グループ権限を実行時に付与することができます。Application Serverでこれらの機能を使用したいときは、独自のプログラムを書かなければなりません。また、Application Serverでの集約は、集約タグ・ライブラリーを使用してプログラマチックに行われます。1つのページに複数のポートレットを表示するには、集約タグ・ライブラリーを使用して、それを実行するコードを書く必要があります。(『リソース 』に記載した連載記事「Exploiting the WebSphere Application Server V6.1 portlet container」を参照してください。)
Tilesフレームワークは、再利用のために共通レイアウトをポータル内のテーマ・テンプレートとして定義するメカニズムを提供します。タイル(テーマ・テンプレートとして)およびポートレット集約(ページ・コンテンツとして)を組み合わせ、ポータルのルック・アンド・フィールをApplication Serverに迅速にインプリメントできます。Tilesタグ・ライブラリーを使用してページ・レイアウト(テーマ)を定義し、ポートレット集約タグ・ライブラリーを使用してポートレットを組み立てます。次に、集約されたポートレットをページ・レイアウト内のタイルにリンクします。Tilesタグおよびポートレット・タグのどちらもパラメーターを受け取ることができるため、カスタマイズされたルック・アンド・フィールおよび動的なコンテンツを作成できます。
この記事では、Struts Tilesタグとポートレット集約タグをApplication Serverで統合し、カスタマイズされたポータル・ページおよびポータルのルック・アンド・フィールを作成する方法を紹介します。説明する内容は以下のとおりです。
Tilesタグとポートレット集約タグを使用して、ページ、メニュー、およびポートレット・レイアウトを作成する。
レイアウトを使用して、カスタマイズされたページを作成する。
レイアウトからポータルを組み立てる。
サンプル・コード は、デモ用にのみ作成されています。しかし、この記事で説明した手法を使用すると、よりお客様指向のルック・アンド・フィールをご自分のアプリケーションにインプリメントすることができます。この記事を読むには、Application Server V6.1でのTiles、ポートレット、およびポートレット・フレームワークに関する基本的な知識と、これらの作成方法および使用方法を理解している必要があります。この記事で取り上げるポートレットは、IBMおよびSunのサンプルJSR 168ポートレット・コード(『リソース 』参照)から得たものです。サンプル・ポートレットはWebSphere Application Server Toolkit 6.1で再パッケージされているので、Application Serverにデプロイできます。
Tilesおよびポートレット集約フレームワークの連携使用
例として、ヘッダー、メニュー、ボディ、およびフッターの各領域で構成されるクラシックなポータル・レイアウトを調べてみましょう(図1参照)。各領域は、コンテンツがパラメーター(ページ、ページ・セグメント、または文字列)として渡される1つのタイルと考えられます。図1に示すように、メニュー領域とボディ領域は、それぞれメニュー・レイアウトおよびボディ・レイアウトでのテンプレートとして定義できます。メニュー・レイアウトは動的なページで構成されます。この各ページは、ポートレット・レイアウトに集約された、異なるポートレットのセットにリンクしています。特定の目的に沿ってサブページ群を編成し、1つのページにグループ化できます。ボディ領域のポートレット・レイアウトは、Application Serverで提供されるポートレット集約タグを使用して集約された、さまざまな数のポートレットで構成されます。
Application Server 6.1では、以下の2つの方法でポータル固有のルック・アンド・フィールを作成できます。
ポータル・ページのカスタマイズを要求するユーザーに基づいて、レイアウト内のタイルおよびサブタイルに異なるパラメーター(ページ、ページ・セグメント、文字列、またはポートレット)を渡す。
レイアウトを変更する、つまり複数のレイアウトを使用する。異なるテーマごとにページ・レイアウトを変更する、異なるスキンごとにポートレット・レイアウトを変更する、およびメニュー・レイアウトを変更してメニュー配置を変える、といったことが可能。
たとえば、トップダウンではなく、階層形式のページ・ナビゲーション・メニューを一番上に水平に表示できます。また、異なるページまたは異なるユーザー・グループに使用する複数のレイアウトを常に作成できます。たとえば、管理者用のポータル・ページに、異なるページ、メニュー、およびポートレット・レイアウトを使用して、ユーザー用のインターフェースと区別することも可能です。
図1. クラシックなポータル・レイアウト
ポータル・レイアウトの作成
次のセクションでは、Tilesタグおよびポートレット集約タグを使用して、ページ、メニュー、およびポートレット・レイアウトを作成する方法について説明します。
ページ・レイアウトの作成
ページ・レイアウトは、ポータル内のすべてのページに共通するテーマを提供します。ポータル内の各ページはページ・レイアウトを呼び出し、ページ・レイアウトで定義されているタイルにパラメーター(ページまたはページ・セグメント)を渡します。<tiles:insert />タグを使用して5つのタイル(タイトル、ヘッダー、メニュー、ボディ、およびフッター)を表の各領域に挿入するクラシックなページ・レイアウトをリスト1に示します。タイルによって占有された領域は、呼び出し側のJSPページから渡されたパラメーターによって満たされます。
リスト1. 各領域にタイルがあるクラシックなページ・レイアウト
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<tiles:importAttribute />
<html>
<head>
<logic:present name="title">
<title><tiles:getAsString name="title" ignore="true"/></title>
</logic:present>
</head>
<body>
<table border="0" cellspacing="0" cellpadding="0" width="100%" bgcolor="#F8FBFE">
<tr>
<td align="left" colspan="2">
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title" beanName="title" beanScope="tile"/>
</tiles:insert>
</td>
</tr>
<tr><td> </td></tr>
<tr>
<td valign="top">
<ul>
<tiles:insert attribute="menu" />
</ul>
</td>
<td>
<div align="center">
<tiles:insert attribute="body" />
</div>
</td>
</tr>
</table>
<tiles:insert attribute="footer" ignore="true"/>
</body>
</html>
ページ・ナビゲーションの作成
ポータル・メニューは、現在ポータルにログインしているユーザーが見ることができるページのリストを表示します。ページ名とリンクのリストを表示するメニュー・レイアウトのコードをリスト2に示します。各リンクは、ポータル・ボディに集約された一連のポートレットを参照します。
リスト2. ポータル・ページのメニュー・レイアウト
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<tiles:useAttribute id="items" name="items" classname="java.util.List" />
<logic:iterate id="item" name="items" type="org.apache.struts.tiles.beans.SimpleMenuItem">
<bean:define id="link" name="item" property="link" type="java.lang.String"/>
<logic:match name="link" location="start" value="/" >
<A href="<%=link%>" >
<bean:write name="item" property="value"/>
</A>
</logic:match>
<logic:notMatch name="link" location="start" value="/" >
<A href="<%=request.getContextPath()%>/<%=link%>">
<bean:write name="item" property="value"/>
</A>
</logic:notMatch>
<P/>
</logic:iterate>
リスト2のメニュー・レイアウトは、Strutsのlogicタグを使用して、ページ名とリンクを繰り返し表示しています。ページおよびそのリンクは、呼び出し側のJSPページによって、Bean (org.apache.struts.tiles.beans.SimpleMenuItem)のリスト(java.util.List)で渡されます。Beanで渡されたリンクが絶対URL("/"で開始)を参照する場合、これはコピーされて表示されます。それ以外の場合は、request.getContextPath()を使用して取得したページ・コンテキストにリンクが追加され、表示されます。
ポートレット・レイアウトの作成
ポータル・ボディには、さまざまな列と行にポートレットが含まれています。ポートレット・レイアウトは、ポータル・ボディ領域の各ポートレット用に、セルのグリッドを定義します。ボディ領域にポートレットを表形式で配置するポートレット・レイアウトのコードをリスト3に示します。このレイアウトでは、ポータル・ボディ内の列数は、呼び出し側のJSPから文字列として渡されます。ポートレットURL、各ポートレットでサポートされているモード、およびポートレットの初期モードは、すべて呼び出し側のJSPページからユーティリティーBean (com.jktelecom.PortletInfo)のリストとして渡されます。このため、呼び出し側のJSPページで、ポートレットの数と配置、初期モード、およびページ内の各ポートレットでサポートされているモードを全体的に制御できるので、各ポートレットからポートレット・レイアウトを変更する必要はありません。
ポートレット・レイアウトは、列数およびポートレット・リストのサイズ(どちらも呼び出し側のJSPページから渡されます)を使用して、ポートレットがレンダリングされる行およびセルの数を決定します。ポートレット・レイアウトは、リスト内の各要素を、元々リストに挿入された順番で反復処理します。そして、サポートされているポートレット・モードを<portlet:state>タグに格納し、ポートレットURIを<portlet:insert> タグに格納することにより、モードおよびポートレット・コンテンツが、対応するセルに動的にレンダリングされるようにします。適切なリンクを持つポートレット・モードは、ポートレット・デプロイメント記述子(portlet.xml)から<portlet:insert>タグによって取得したポートレット・タイトルとともに表示されます。
リスト3. ポートレット・レイアウト
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="http://ibm.com/portlet/aggregation" prefix="portlet" %>
<%@ page import="java.util.*" %>
<%@ page import="com.jktelecom.*" %>
<%@ page isELIgnored ="false" %>
<%
String page_uri = (String)session.getAttribute("Current_Page");
String uri_prefix = PageInfo.getPageName(page_uri) +"/";
%>
<portlet:init portletURLPrefix="<%=uri_prefix%>" >
<tiles:importAttribute />
<table border="1">
<%-- Prepare the links list to be iterated --%>
<bean:define id="portlets" name="portlets" type="java.util.List" />
<bean:define id="numColumns" name="numColumns" type="java.lang.String" />
<%
int cols = Integer.parseInt(numColumns);
Iterator loop = portlets.iterator();
int portlet_count = 0;
while (loop.hasNext()) {
%>
<!-- create portal table with number columns defined by variable cols -->
<tr bgcolor="#e0eaf8">
<%
String[] portRefs = new String[cols];
for (int i=0; i < cols; i++) {
if (!loop.hasNext()) {
break;
}
PortletInfo portletInfo = (PortletInfo)loop.next();
portRefs[i] = portletInfo.getName();
String windowId = String.valueOf(portlet_count);
%>
<!-- insert portlet title bar -->
<td>
<table width="100%">
<tr>
<td>
<b><span id="title_<%=portlet_count%>">Portlet <%=
portlet_count%></span></b>
</td>
<td align="right">
<%
String portletName = portletInfo.getName();
String[] portletModes = portletInfo.getSupportedModes(portletName);
for (int j=0; j < portletModes.length; j++ ) {
%>
<a href="<portlet:state url='<%=portletName%>'
windowId='<%=windowId%>'
portletMode='<%=portletModes[j]%>' />">
<%=portletModes[j]%> </a>
<%
}
%>
</td>
</tr>
</table>
</td>
<%
portlet_count++;
}
%>
</tr>
<tr>
<%
for (int k=0; k < cols; k++) {
int title_num = portlet_count-cols+k;
String windowId = String.valueOf(title_num);
%>
<td>
<!-- insert portlet -->
<portlet:insert url="<%=portRefs[k]%>" windowId="<%=windowId%>"
titleVar="title" />
</td>
<!-- insert portlet title -->
<script type="text/javascript">
document.getElementById("title_<%=title_num%>").firstChild.nodeValue = "${title}";
</script>
<%
}
%>
</tr>
<tr><td colspan="<%=cols%>"> </td></tr>
<%
}
%>
</table>
</portlet:init>
リスト3に示すように、ポートレット・レイアウトで以下の問題を解決する必要があります。
URL接頭部の設定
initポートレット集約タグのportletUrlPrefix属性には、適切なURL接頭部を指定する必要があります。
この接頭部は、stateタグおよびinsertタグによって作成されるポートレットURLで使用されます。これは、集約コンテキストと集約機能マッピングの2つの部分で構成されます。URLに相対パスを使用する場合は、ポートレット・コンテナーが開発者に代わって集約コンテキストを管理します。しかし、URLに絶対パス(たとえば、/jkTelecom/Tools/)を使用する場合は、ポータル・アプリケーション(WAR)をApplication Serverにデプロイするときに、開発者は集約コンテキストで使用したものと同じコンテキスト・ルート(jkTelecom)を指定する必要があります。開発者はWebアプリケーション・デプロイメント記述子(web.xml)でURLの集約マッピング部を構成し、現在のページによって参照されるURLを指定する必要があります。これは、ポートレット集約(portlet layout)を表示します。
たとえば、現在のポートレット集約が、tools.jspを参照するToolsページによって呼び出される場合は、ポートレットURLはtools.jspにマッピングしなければなりません。マッピングの詳細については、以下の『ポータルの構成 』セクションで説明します。
適切な集約機能マッピングを設定するには、ユーザーが現在見ているページをトラッキングし、それに応じて集約機能マッピングを設定する必要があります。サンプル・コードは、以下のようにトラッキングを処理します。
ユーザーがメニューでページ・リンクをクリックすると、コードはページURLをユーザーのセッション(たとえば、tools.jsp)に格納します。
<%
String current_page = "tools.jsp";
session.setAttribute("Current_Page", current_page);
%>
ポートレット・レイアウト(portletLayout.jsp)で、そのセッションからURLを取得します。
<%
String page_uri = (String)session.getAttribute("Current_Page");
String uri_prefix = PageInfo.getPageName(page_uri) +"/";
%>
PageInfo.javaクラスで定義されたマップから、URLのマッピングを取得します(リスト4)。ユーティリティー・クラスPageInfo.javaには、web.xml内のマッピングに対応するURLへのすべてのマッピングが含まれています。
リスト4. ページ・マッピング
static HashMap pages;
static {
pages = new HashMap();
pages.put("index.jsp", "Home");
pages.put("account.jsp", "Account");
pages.put("tools.jsp", "Tools");
pages.put("reports.jsp", "Report");
pages.put("services.jsp", "Services");
...
}
public static String getPageName(String uri) {
return (String)pages.get(uri);
}
最後に、ポートレット集約機能のinitタグのportletURLprex属性に、集約機能マッピングが割り当てられます。
<portlet:init portletURLPrefix="<%=uri_prefix%>"
ポートレット・モードの処理
通常、各ポートレットはさまざまなモード(表示、編集、およびヘルプなど)をサポートし、モードのアイコンがポートレットのタイトルとともにポータル内に表示されます。アイコンを表示する前に、ポートレットがどのモードをサポートするのかを把握する必要があります。そうしないと、サポートされているモードがポートレットから失われてしまうか(モードのアイコンを表示しない場合)、あるいは例外がスローされます(表示されたモードがポートレットによってサポートされていない場合)。
ポートレット・モードの情報は、ポートレット・デプロイメント記述子の<supports>セクションにあります(リスト5)。
リスト5. ポートレット・デプロイメント記述子(portlet.xml)の一部
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>config</portlet-mode>
<portlet-mode>edit</portlet-mode>
<portlet-mode>help</portlet-mode>
</supports>
ポートレット集約タグ<portlet:insert>を使用して取得するポートレット・タイトルとは異なり、サポートされているモードを取得するために利用できるポートレット集約タグはありません。ポートレット・デプロイメント記述子を参照し、ご自分で取得しなければなりません。サンプル・コードで使用されるすべてのポートレットでサポートされているモードはハッシュ・マップに格納されているので、動的に取得できます(リスト6)。
リスト6. サポートされているポートレット・モード
static HashMap supportedModes;
static {
supportedModes = new HashMap();
supportedModes.put("IBMSamples/HelloWorld", new String[]{"view"});
supportedModes.put("IBMSamples/WorldClock", new String[]{"view", "edit", "help"});
supportedModes.put("IBMSamples/SQLQuery", new String[]{"view"});
supportedModes.put("IBMSamples/HelloJSP", new String[]{"view"});
supportedModes.put("SunSamples/JSPPortlet", new String[]{"edit", "help"});
supportedModes.put("SunSamples/NotepadPortlet", new String[]{"edit", "help"});
supportedModes.put("SunSamples/BookmarkPortlet", new String[]{"edit", "help"});
}
public String[] getSupportedModes(String portletName) {
return (String[])supportedModes.get(portletName);
}
ポータルの組み立て
このセクションでは、ページ、メニュー、およびポートレット・レイアウトを使用して、カスタマイズされたポータル・ページを作成するJSPの書き方について説明します。また、ポートレット集約マッピングをサポートするWebアプリケーション記述子(web.xml)の構成方法についても説明します。
ページ・レイアウトの使用
呼び出し側のJSPページは、ページ・レイアウトに挿入されるパラメーターを渡します。現在のユーザーおよびそのユーザーに表示するコンテンツに基づき、他のJSPページ、ページ・セグメント、または単純な文字列をパラメーターにすることができます。
リスト7に、デフォルトのページ・レイアウト定義のコードを示します。この定義は、ページ・レイアウトに渡されるデフォルトのパラメーターを指定します。たとえば、ページ・レイアウトのヘッダー・タイルにはheader.jspファイルが渡され、フッター・タイルにはfooter.jspファイルが渡されます。
リスト7. デフォルトのページ・レイアウト定義
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<logic:notPresent name="pageLayoutDef" scope="request" >
<tiles:definition id="pageLayoutDef" page="/pageLayout.jsp" scope="request" >
<tiles:put name="title" type="string" value="jkTelecom Portal" />
<tiles:put name="header" value="/header.jsp" />
<tiles:put name="footer" value="/footer.jsp" />
<tiles:put name="body" value="/default_body.jsp" />
<tiles:put name="menu" value="/default_menu.jsp" />
</tiles:definition>
</logic:notPresent>
呼び出し側のJSPページは、異なるパラメーターを渡すことにより、ページ・レイアウト定義で定義されたデフォルトの動作をオーバーライドすることもできます。リスト8では、呼び出し側のJSPページ(tools.jsp)はリスト7のページ・レイアウト定義を使用します。そして、menu.jspおよびportlets.jspを使用して、デフォルトのメニュー・ページ(default_body.jsp)とボディ・ページ(default_menu.jsp)をオーバーライドします。
リスト8. ページ・レイアウトを使用するポータル・ページ(tools.jsp)
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%
String current_page = "tools.jsp";
session.setAttribute("Current_Page", current_page);
%>
<jsp:include page="/pageLayoutDef.jsp" />
<tiles:insert beanName="pageLayoutDef" flush="true" beanScope="request">
<tiles:put name="body" value="/portlets.jsp" />
<tiles:put name="menu" value="/menu.jsp" />
</tiles:insert>
ページ・ナビゲーションの使用
メニュー・レイアウトを使用するポータル・メニュー(menu.jsp)をリスト9に示します。ポータル・メニューは、jsp:useBeanを使用してSimpleMenuItemのインスタンスを作成します。次に、jsp:setPropertyを使用して、SimpleMenuItem Beanのlinkプロパティーとvalueプロパティーを設定します。最後に、tiles:addを使用してBeanをリストに追加します。
メニューは、ユーザー・グループに基づいてカスタマイズされ、メニュー・レイアウトを変更せずに、役割ベースのページが作成されます。このため、ユーザーが特定の役割に属し、ページへのアクセス権を持つ場合にのみ、ページを表示することができます。ユーザーの役割は、要求オブジェクトのisUserInRoleメソッドによって決められます。
リスト9. メニュー・レイアウトを使用するポータル・ページ・メニュー
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:importAttribute />
<tiles:insert page="/menuLayout.jsp" flush="false" >
<tiles:putList name="items" >
<jsp:useBean id="item_0" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_0" property="link" value="index.jsp" />
<jsp:setProperty name="item_0" property="value" value="Home" />
<tiles:add beanName="item_0" />
...
<%
if (request.isUserInRole("Managers")){
%>
<jsp:useBean id="item_4" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_4" property="link" value="tools.jsp" />
<jsp:setProperty name="item_4" property="value" value="Tools" />
<tiles:add beanName="item_4" />
...
<%
} else if (request.isUserInRole("Users")) {
%>
<jsp:useBean id="item_8" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_8" property="link" value="services.jsp" />
<jsp:setProperty name="item_8" property="value" value="Services" />
<tiles:add beanName="item_8" />
...
<%
}
%>
</tiles:putList>
</tiles:insert>
ポートレット・レイアウトの使用
メニュー・レイアウトを使用するJSPページ(menu.jsp)をリスト10に示します。ポートレットがボディ内でレンダリングされる列数と、<jsp:useBean>によって作成されたBean (com.jktelecom.PortletInfo)のリストが、ポートレット・レイアウトに渡されます。Beanには、ポートレット・レイアウトがポートレットをレンダリングするために必要なすべての情報(ポートレットURL、初期モード、およびサポートされているモデル)が含まれています。
リスト10. ポートレット・レイアウトを使用するJSPページ
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ page import="java.util.*" %>
<%@ page import="com.jktelecom.*" %>
<tiles:insert page="/portletLayout.jsp" flush="false" >
<!-- create portal table of two columns -->
<%
if (request.isUserInRole("Managers")) {
%>
<tiles:put name="numColumns" value="3" />
<%
} else {
%>
<tiles:put name="numColumns" value="2" />
<%
}
%>
<!-- pass portlet links -->
<tiles:putList name="portlets" >
<jsp:useBean id="portlet_0" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_0" property="name"
value="IBMSamples/HelloWorld" />
<jsp:setProperty name="portlet_0" property="initialMode"
value="<%=PortletInfo.VIEW%>" />
<tiles:add beanName="portlet_0" />
<%
if (request.isUserInRole("Managers")) {
%>
<jsp:useBean id="portlet_1" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_1" property="name"
value="SunSamples/JSPPortlet" />
<jsp:setProperty name="portlet_1" property="initialMode"
value="<%=PortletInfo.EDIT%>" />
<tiles:add beanName="portlet_1" />
…
<%
} else if (request.isUserInRole("Users")) {
%>
<jsp:useBean id="portlet_6" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_6" property="name"
value="IBMSamples/WorldClock" />
<jsp:setProperty name="portlet_6" property="initialMode"
value="<%=PortletInfo.VIEW%>" />
<tiles:add beanName="portlet_6" />
…
<%
}
%>
</tiles:putList>
</tiles:insert>
リスト8に示したように、列数およびポートレットのリストは、役割ベースで設定されます。また、呼び出し側のJSPからポートレットへのアクセス権を制御できます。以下に示すカスタマイズをさまざまな方法でインプリメントできます。
ユーザーが特定の役割に属し、ポートレットへのアクセス権を持つ場合にのみ、ユーザーはポートレットを見ることができます。これにより、特定のユーザーまたはユーザー・グループのために、ポートレット・レイアウトにポートレットを選択的に渡すことができます。ポートレットへのアクセス権を持たないユーザーは、ポータル内でこれらのポートレットを見ることができません。
さらに細かく権限を制御するために、特定のユーザーまたはグループに対し、ポートレットで利用できるモードをより詳細に制限できます。たとえば、認証されたユーザーにのみ編集アイコンを表示することにより、匿名ユーザーによるポートレットの編集をブロックできます。
ポートレット・レイアウトを変更せずに、ポートレット数および列数をポートレット・レイアウトに渡すことができます。
ポータルの構成
ポートレットを含む複数のページを1つのポータルに統合するには、ポートレットURLを処理する特殊なアクションを実行する必要があります。ユーザーが異なるポートレット・モードをクリックすると、他のすべてのポートレットおよびページ全体が更新され、ポートレット内のフォーム・データが再ポストされます。
集約タグ・ライブラリーを使用するときは、initタグのportletUrlPrefix属性に、適切な集約機能のコンテキストおよびマッピングを設定しなければなりません。集約機能コンテキストは、現在のアプリケーションのコンテキスト・ルートです。前のポートレット・レイアウトのセクションで説明したように、集約機能マッピングは現在のページを参照する必要があります。
アプリケーション・デプロイメント記述子(web.xml)内のすべてのポータル・ページにマッピングを定義し、集約機能マッピングが正しいJSP ページを参照するようにしてください(リスト11)。web.xmlで定義したマッピングはユーティリティー・クラスPageInfo.javaで利用できるため、マッピングを直接取得することができます。
リスト11. ポータル・アプリケーションのデプロイメント記述子(web.xml)
…
<servlet>
<servlet-name>Home</servlet-name>
<jsp-file>index.jsp</jsp-file>
</servlet>
<servlet>
<servlet-name>Tools</servlet-name>
<jsp-file>tools.jsp</jsp-file>
</servlet>
…
<servlet-mapping>
<servlet-name>Home</servlet-name>
<url-pattern>/Home/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Tools</servlet-name>
<url-pattern>/Tools/*</url-pattern>
</servlet-mapping>
…
リスト11では、JSPページ(index.jsp)は架空のサーブレットHomeのインプリメンテーションとして定義されています。集約マッピングのパターン/Home/*は、Homeサーブレットを示しています。パターン/Home/*をともなうURLは、JSPページ(index.jsp)として動的に解決されます。このマッピングの関係を図2に示します。この図では、web.xmlからのマッピングが、ポートレット・モード・アイコンへのリンクのURLにどのように表示されるのかが示されています。
たとえば、initタグのportletUrlPrefix属性で相対URLのHomeが集約機能マッピングに指定されているときは(jkTelecomがコンテキスト・ルート)、集約パターン/Home/はindex.xmlとして解決されます。ユーザーがページ内のポートレットの任意のアイコン(表示、編集、およびヘルプ)をクリックすると、要求されたポートレット・モードのフォーム・データが再ポストされ、他のポートレットを含むページ全体が更新されます。このマッピングの関係を図2に示します。
図2. マッピングの関係
ポータルのデプロイ
アプリケーションはWARファイルとしてパッケージし、任意のWebアプリケーションとしてデプロイします。サンプル・コードをデプロイしたポータルを図3と4に示します。コンテキスト・ルートは、jkTelecomとして指定されています。initタグのPortletUrlPrefix属性で相対パスを使用すると(ポートレット・レイアウトのセクションで説明したように)、任意の文字列をコンテキスト・ルートとして使用できます。それ以外の場合は、集約コンテキストで使用したのと同じコンテキスト・ルートを指定しなければなりません。
図3. デプロイ済みポータル(ユーザーは「Managers」役割を持つsara)
図4. デプロイ済みポータル(ユーザーは「Users」役割を持つfred)
まとめ
この記事では、Struts Tileタグおよびポータル集約タグを使用して、共通ポータル・レイアウト(ページ、ナビゲーション、およびポートレット・レイアウト)を再利用可能なテンプレートとして作成する方法について説明しました。レイアウトを使用して動的なWebページの作成ができ、またレイアウトからポータルを組み立てることができます。また、開発およびデプロイメントの問題を解決し、開発の労力を軽減する方法についても説明しました。WebSphere Application Serverポートレット・コンテナーおよび集約タグを使用し、この記事に書かれている情報を適用することにより、独自のポータル・ページを作成できます。
ダウンロード
ディスクリプション
ファイル名
サイズ
ダウンロード方法
コード・サンプル
webportal-samples.zip
1,990 KB
HTTP(US)
リソース
筆者について(原文のまま)
Shunguo Yan is an Advisory Software Engineer in the Application and Integration Middleware division of IBM software group in Austin. He currently works on WebSphere Telecom Web Service Server and the IP Multimedia Subsystem (IMS) Solution. His major responsibility is to design and develop integrated solutions for various industries using J2EE, XML, Web services, and IBM software products.