【コラム】

Java API、使ってますか?

26 次期Javaポートレット仕様となるJSR 286

26/60

JSR 286: Portlet Specification 2.0

Javaポートレット仕様の現行バージョンは第23回でも紹介したJSR 168だが、現在はその後継バージョンとなる「JSR 286: Portlet Specification 2.0」の仕様策定が進められている。

2.0では新たに次のような機能が追加される予定となっている。

  • イベント処理 - ポートレット間でイベントの送受信が可能
  • レンダーパラメータ - 他のポートレットとレンダーパラメータを共有できる
  • リソースサービング - 画像などのリソースにポートレット経由でアクセスできる
  • ポートレットフィルター - リクエストおよびレスポンスの途中で情報の変換を行うことが可能

その他、1.0では曖昧であったポートレットの振る舞いのいくつかを明確にすることや、ローカライゼーションの記述をportlet.xmlではなくリソースバンドルに記述できるようにするなどといった変更が加えられる予定。

2.0は1.0との互換性が保たれるため、1.0に準拠したポートレットはそのまま2.0のコンテナでで動作させることができる。また、ターゲットとなるプラットフォームはJava SE 5.0で、J2SE 1.4で動作させる場合にはアノテーションやジェネリクス、Enumを利用したいくつかの機能が使えなくなるとのこと。

現在JSR 286はPublic Review Ballotを賛成多数で通過した段階にある。Public DraftはJCPのサイトから入手することができる。

JSR 286対応のポートレットコンテナを試す

OpenPortalによるPortlet Container Projectでは、JSR 286対応のPortletコンテナがPortlet Container 2.0として開発されている。最新の成果物は、Subversionリポジトリよりプロンプト1のようにしてチェックアウトできる。guestユーザのパスワードは空でよい。

プロンプト1 Subversionリポジトリのチェックアウト

svn checkout https://portlet-container.dev.java.net/svn/portlet-container/branches/portlet_2_branch portlet-container --username guest

チェックアウトしたらportlet-containerのディレクトリに移動し、Apache Mavenを利用してプロンプト2のようにしてビルドする。

プロンプト2 Poerlet Containerのビルド

> mvn package
> mvn verify

ビルドに成功すると/distディレクトリにportlet-container-configurator.jarというファイルが生成される。これを第25回の例と同様にGlassFishにデプロイする(プロンプト3)。

プロンプト3 Portlet Conatinerのデプロイ

> java -jar portlet-container-configurator.jar

準備ができたら、早速2.0の新しい機能を使ったポートレットを作成してみよう。今回はイベントを利用したポートレット間通信を試してみようと思う。プロジェクト作成の際には、/dist/portlet-container/lib以下にあるすべてのJARファイルがクラスパスに含まれるようにしておく。

まず、送受信するイベントの定義を/WEB-INF/portlet.xmlに記述する。イベント定義はリスト1のようにタグで行う。イベント名はXML名前空間のQNameを用いて定義し、で型を指定する。

リスト1 /WEB-INF/portlet.xml - 送受信するイベントの定義

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app version="1.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet" 
    xmlns="http://java.sun.com/xml/ns/portlet">

    <event-definition>
        <qname xmlns:x="http:mycom.co.jp/events">x:message</qname>
        <value-type>java.lang.String</value-type>
    </event-definition>

    <portlet>
        <portlet-name>SendMessagePortlet</portlet-name>
        <display-name>Send Message Portlet</display-name>
        <portlet-class>apisample.portlet.SendMessagePortlet</portlet-class>

        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>

        <supported-publishing-event xmlns:x="http:mycom.co.jp/events">
            x:message
        </supported-publishing-event>

        <portlet-info>
            <title>Send Message</title>
        </portlet-info>
    </portlet>

    <portlet>
        <portlet-name>ReceiveMessagePortlet</portlet-name>
        <display-name>Receive Message Portlet</display-name>
        <portlet-class>apisample.portlet.ReceiveMessagePortlet</portlet-class>

        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>

        <supported-processing-event xmlns:x="http:mycom.co.jp/events">
            x:message
        </supported-processing-event>

        <portlet-info>
            <title>Receive Message</title>
        </portlet-info>
    </portlet>
</portlet-app>

次にイベントの送信側のポートレットを作成する。ページはリスト2のようにJSPファイルで作成し、これをリスト3においてPortletRequestDispatcherを利用してポートレットにディスパッチしている。

このポートレットは、テキストフィールドにメッセージを入力してボタンを押したら、その内容がイベントを介して受信側のポートレットに送られるというもの。ボタンが押されるとprosessAction()メソッドが呼び出され、ActionRequestからパラメータの内容を取得できる。イベントの送信はActionResponseのsetEvent()メソッドによって、イベント名と値をセットすることで行える。

リスト2 /WEB-INF/jsp/input.jsp - イベント送信側のポートレットページ

<?xml version="1.0" encoding="UTF-8" ?>

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
        xmlns:portlet="http://java.sun.com/portlet">
    <jsp:directive.page language="java"
        contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" />

    <portlet:actionURL var="viewUrl" portletMode="view"/>

    <h3>メッセージ入力</h3>
    <form action="${viewUrl}" method="post">
        <input type="text" name="message" value="${message}"/><br/>
        <input type="submit" name="send" value="Send"/>
    </form>

</jsp:root>

リスト3 SendMessagePortlet.java - イベント送信側のポートレットプログラム

package apisample.portlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.xml.namespace.QName;

public class SendMessagePortlet extends GenericPortlet {
    private PortletContext portletContext;

    public void init(PortletConfig config) throws PortletException {
        super.init(config);
        portletContext = config.getPortletContext();
    }

    public void processAction(ActionRequest request, ActionResponse response) {
        String myMessage = request.getParameter("message");
        // イベントを送信
        QName qname = new QName("http:mycom.co.jp/events", "message");
        response.setEvent(qname, myMessage);
    }

    public void doView(RenderRequest request, RenderResponse response)
        throws PortletException, IOException {
        response.setTitle("Send Message Portlet");
        response.setContentType(request.getResponseContentType());

        // ページの出力をJSPファイルにディスパッチ
        try {
            PortletRequestDispatcher dispatcher = 
                    portletContext.getRequestDispatcher("/WEB-INF/jsp/input.jsp");
            dispatcher.include(request, response);
        } catch (IOException e) {
            throw new PortletException("SendMessagePortlet.doView exception", e);
        }
    }
}

/WEB-INF/portlet.xmlには、SendMessagePortletのための定義をとしてリスト4の内容を追加する。ここでは、イベントの送信を有効にするためにタグによって送信したいイベントを指定しておく必要がある。

リスト4 /WEB-INF/portlet.xml - SendMessagePortletのための定義を追加

    <portlet>
        <portlet-name>SendMessagePortlet</portlet-name>
        <display-name>Send Message Portlet</display-name>
        <portlet-class>apisample.portlet.SendMessagePortlet</portlet-class>

        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>

        <supported-publishing-event xmlns:x="http:mycom.co.jp/events">
            x:message
        </supported-publishing-event>

        <portlet-info>
            <title>Send Message</title>
        </portlet-info>
    </portlet>

続いてイベント受信側のポートレットを作成する。/WEB-INF/portlet.xmlに記述するポートレット定義はリスト5のようになる。ここで、タグによって受信するイベントの名前を設定しておくことで、このイベントが送信された際にそれをポートレットで受け取って処理することが可能になる。

リスト5 /WEB-INF/portlet.xml - ReceiveMessagePortletのための定義を追加

    <portlet>
        <portlet-name>ReceiveMessagePortlet</portlet-name>
        <display-name>Receive Message Portlet</display-name>
        <portlet-class>apisample.portlet.ReceiveMessagePortlet</portlet-class>

        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>

        <supported-processing-event xmlns:x="http:mycom.co.jp/events">
            x:message
        </supported-processing-event>

        <portlet-info>
            <title>Receive Message</title>
        </portlet-info>
    </portlet>

ポートレットのプログラムは(gsld:ReceiveMessagePortlet.java)のようにする。イベントを受け取るとprosessEvent()メソッドが実行される。そこでEventRequestからイベントを取り出し、メッセージの中身をEventResponseに対してパラメータとして渡している。

表示部分はリスト6にディスパッチする。

リスト6 ReceiveMessagePortlet.java - イベント受信側のポートレットプログラム

package apisample.portlet;

import java.io.IOException;
import javax.portlet.Event;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class ReceiveMessagePortlet extends GenericPortlet{
    private PortletContext portletContext;

    public void init(PortletConfig config) throws PortletException {
        super.init(config);
        portletContext = config.getPortletContext();
    }

    public void processEvent(EventRequest request, EventResponse response) {
        // イベントを受信
        Event event = request.getEvent();
        if(event.getName().equals("message")) {
            String myMessage = (String)event.getValue();
            response.setRenderParameter("message", myMessage);
        }
    }

    public void doView(RenderRequest request, RenderResponse response)
        throws PortletException, IOException {
        response.setTitle("Receive Message Portlet");
        response.setContentType(request.getResponseContentType());

        String message = request.getParameter("message");
        if (message == null) {
            message = "";
        }
        request.setAttribute("message", message);

        // ページの出力をJSPファイルにディスパッチ
        try {
            PortletRequestDispatcher dispatcher = 
                    portletContext.getRequestDispatcher("/WEB-INF/jsp/output.jsp");
            dispatcher.include(request, response);
        } catch (IOException e) {
            throw new PortletException("ReceiveMessagePortlet.doView exception", e);
        }
    }
}

リスト7 /WEB-INF/jsp/output.jsp - イベント受信側のポートレットページ

<?xml version="1.0" encoding="UTF-8" ?>

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
    xmlns:portlet="http://java.sun.com/portlet">
    <jsp:directive.page language="java"
        contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" />

    <portlet:actionURL var="viewUrl" portletMode="view"/>

    <h3>メッセージ出力</h3>
    <h2>${message}</h2>

</jsp:root>

なお、/WEB-INF/web.xmlに対しては今回は特に設定することがないので、リスト8のようにくらいを記述しておけばよい。

リスト8 /WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
     version="2.5">

    <display-name>PortletEventSample</display-name>
</web-app>

両ポートレットを同じWARファイルにまとめるとすると、ファイルの構成は図1のようになる(必要なライブラリを/WEB-INF/libディレクトリに配置した場合)。

図1 WARファイルの構成

これをGlassFishのポートレットコンテナにデプロイし、WEBブラウザから

http://localhost:8080/portletdriver/

にアクセスすると図2のように2つのポートレットが表示される。「Send Message Portlet」側にメッセージを入力してボタンをクリックすれば、それが「Receive Message Portlet」側に反映されるはずだ(図3)。

図2

図3

26/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。



人気記事

一覧

イチオシ記事

新着記事