ポータルの作成
WLPのようなポータルフレームワークが優れているのは、利用者は単にコードを書くだけでよく、全体がどのように統合プレゼンテーションおよびナビゲーションモデルへと集約されるかを気にしないで済むしくみを提供する点です。こうしたフレームワークのメリットを十二分に活かすため、自らデザインするのでなく、デフォルトで備わっている基本機能を常に使いたいところです。IFrameを使ってレガシーアプリケーションをポータル内にレンダリングする場合も、基本機能を使って実現できます。ただし、しくみを理解するためには別の角度からも考えてみた方がいいでしょう。
ポータルは基本的にヘッダー、ナビゲーション、コンテンツ、フッターで構成されます。ポータルにおけるコンテンツは、基本的にはポートレットです。コンテンツエリアは複数のポートレットを格納する設計になっており、コンテンツエリア全体を1つのIFrameで埋めるにはやや手間がかかります。コンテンツのサイズを意識しないで済むようIFrameを定義する最も簡単な方法は、高さと幅を100%に設定することです。しかし、100%×100%のIFrameを含んだJSPを格納するポートレットを生成しても、設計時にポートレットのプロパティまたはCSSを通じて定義した分のスペースが表示されるだけです。図1に、設計時に何も定義しなかった場合のシナリオを示します。
それでは、もっと詳しく見ていきましょう。ポータルを構成する主な要素は、ヘッダー、ナビゲーション、コンテンツ、フッターです。この4つの要素のうちヘッダー、ナビゲーション、フッターの3つは、ルックアンドフィールフレームワーク内(具体的にはスケルトン内)の直接対応する部分でレンダリングされます(少々大雑把な説明ですが、今回の話の流れでは十分でしょう)。残る1つはコンテンツですが、これは複数のスケルトンファイルによってレンダリングされます。ポートレットが1つだけのページであれば、基本となるスケルトンファイル群はpage.jsp、gridlayout.jsp、placholder.jsp、titlebar.jsp、window.jspになるでしょう。これに対応するHTMLは次のようになります。
<div class="bea-portal-book-primary-page">
<table class="bea-portal-layout-grid" cellspacing="0">
<tr>
<td class="bea-portal-layout-placeholder-container">
<div class="bea-portal-layout-placeholder" >
<div class="bea-portal-window" width="100%">
<div class="bea-portal-window-content">
<IFRAME id="example1"
NAME="example1"
SRC="http://www.developer.com/"
frameborder="0"
width="100%"
height="100%"
align="middle"
marginheight="0"
marginwidth="10"
scrolling="auto">
</IFRAME>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
ここでの目標は、ポータルページ全体をIFrameで埋めることです。しかし、グリッドレイアウトやプレースホルダー、ウィンドウ(タイトルバーはポートレットのプロパティで非表示にされています)に関する余分なマークアップがあるため、目標を実現するのは簡単ではありません。この問題を解決するには、該当のページを使用するだけのテーマを作ります。このテーマは、編纂用のページを構成する前述のスケルトンファイルすべてを必要としますが、実際にそれらのファイルを使うことはありません。page.jsp以外のファイルは、すべて空でなければいけません。page.jspの内容は次のようになります。
<%@ page import="java.net.URLDecoder,
com.bea.netuix.servlets.controls.page.PagePresentationContext,
com.bea.netuix.servlets.controls.page.BookPresentationContext,
org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils"
%>
<%@ page session="false"%>
<%@ taglib
uri="http://www.bea.com/servers/portal/tags/netuix/render"
prefix="render" %>
<%! static final String URL_KEY = "urlKey";%>
<render:beginRender>
<%
PagePresentationContext pageCtx =
PagePresentationContext.getPagePresentationContext(request);
String urlKey = pageCtx.getPresentationId();
String iFrameUrl = ScopedServletUtils.getOuterRequest(request).
getSession().getServletContext().getInitParameter(urlKey);
%>
<div style="margin-top:-5px">
<IFRAME id="<%=urlKey %>"
NAME="<%=urlKey %>"
SRC="<%=iFrameUrl %>"
frameborder="0"
width="100%"
height="100%"
align="middle"
marginheight="0"
marginwidth="10"
scrolling="auto">
</IFRAME>
</render:beginRender>
<render:endRender>
</div>
</render:endRender>
ここでは2つの変数(urlKeyとiFrameUrl)によって拡張性を実現しています。urlKeyは設計時にページプロパティで定義します。さらに、web.xmlでiFrameUrlを次のように設定します。
<context-param> <param-name>IFRAME_URL1</param-name> <param-value>http://www.developer.com/</param-value> </context-param>
ポータル内でサンプルを実行させるときは、結果のHTMLはもっと簡単になります。
<div class="bea-portal-book-primary-content">
<span class="bea-portal-theme-iframe2">
<div style="margin-top:-5px">
<IFRAME id="IFRAME_URL1"
NAME="IFRAME_URL1"
SRC=http://www.developer.com/
frameborder="0"
width="100%"
height="100%"
align="middle"
marginheight="0"
marginwidth="10"
scrolling="auto">
</IFRAME>
</div>
</span>
</div>
また、画面には図2のように思いどおりの結果が表示されます。
このアプローチのバリエーションとして、ページのプレゼンテーションIDの代わりにポートレットとバッキングファイルを使用する方法があります。このアプローチでは、URLを値として持つurlKeyのプリファレンスと、その値をリクエストにセットするバッキングファイルが必要です。これにより、urlKeyはservletContextからではなく、リクエストから取得されるようになります。バッキングファイルのコードは、たとえば次のような形で記述することができます。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.bea.netuix.servlets.controls.content.backing. AbstractJspBacking; import com.bea.netuix.servlets.controls.portlet.backing. PortletBackingContext; public class IframePathBacking extends AbstractJspBacking { private static final long serialVersionUID = 1L; private static final String URL_KEY = "urlKey"; public boolean preRender(HttpServletRequest request, HttpServletResponse response) { PortletBackingContext pbc = PortletBackingContext.getPortletBackingContext(request); String urlKey = pbc.getInstanceLabel(); request.setAttribute(URL_KEY, urlKey); return true; } }
実行時にアプリケーションを再起動させずにIFrameページの一部または全部を定義する必要がある場合は、ポートレットによるアプローチの方が優れています。
最後に1つ注意しておくことがあります。100%の高さ指定を行う方法は、Windows Vistaでは機能しません(少なくとも、当記事の執筆中に事象を発見したVista Ultimateではそうです)。このことは、すぐにでもポートレットにアップグレードする必要があると主張する理由になるでしょう。ただしこの問題は、高さを固定する(アプリケーション全部が同一サイズで利用できる場合)、ポートレットのプリファレンスで高さを指定する(ポートレットとバッキングファイルを用いる方法の場合)、またはJavaScript機能で動的にIFrameの高さを指定するといった方法で回避可能です。


