DWR が Ajax によるポートレット間メッセージングを簡単にする

Java ポートレットと Ajax は Web 開発に最適です

多くの開発者は、Web ベース・アプリケーションのユーザー・エクスペリエンスを向上させるために Ajax テクノロジーを使おうとしますが、Ajax プログラミングは厄介な作業です。ところが、オープン・ソースの DWR (Direct Web Remoting ) ライブラリーを使うと、Java™ クラスが JavaScript クラスに自動的に変換されるため、Java 開発者は Ajax 開発を簡単に行うことができます。この記事では、DWR と JSR-168 準拠のポートレットを使って、Ajax アプリケーションを素早く簡単にビルドする方法を学びます。

Sami Salkosuo (sami.salkosuo@fi.ibm.com), Software Architect, IBM

author photoSami Salkosuo は、1999 年から IBM に勤めています。主な関心分野は Java プログラミングで、Sun Certified Java Programmer、IBM Certified Solution Developer for XML and Related Technologies、および IBM Certified Solution Developer for IBM WebSphere Portal です。Java テクノロジーの他に、Python、Fortran、LabVIEW、Visual Basic、LISP、Perl、および PHP の経験もあります。


developerWorks 貢献著者レベル

2006年 7月 14日

ポートレットは、Web ポータルのための Java プラットフォーム・ベースのアプリケーションです。JSR-168 は、ポートレット・アプリケーションを開発するための Java Community Process 標準であり、ポートレットのライフ・サイクル管理、ポートレット・コンテナーの契約、パッケージ化、デプロイメント、その他のポータルに関連する側面について扱います。

Asynchronous JavaScript + XML、すなわち Ajax は、高度な対話式の Web アプリケーションを開発するための手法です。Ajax は、XML、HTML、DHTML、JavaScript、および DOM を組み合わせて使います。

ポートレットと Ajax は、両方ともユーザーに UI を表示するための手段として Web ブラウザーを使うようにフォーカスしているため、お互いに最適な組み合わせです。この 2 つを Java テクノロジーと組み合わせるには、DWR ライブラリーを使うと簡単です。DWR は、Ajax ベースの Web アプリケーションをビルドするための Java ライブラリーで、Apache ライセンスを受けたオープン・ソースです。DWR の基本的な目的は、Ajax の詳細を開発者から見えなくすることです。このため、サーバー・サイドで POJO (Plain Old Java Object) を使用すると、DWR は JavaScript プロキシー機能を動的に生成し、JavaScript によるクライアント・サイドの開発は JavaBeans を直接呼び出すような感じになります。DWR の主要コンポーネントは、ブラウザーからサーバーへの呼び出しを処理する Java サーブレットです。

この記事では、DWR を使って、3 つのポートレットを基にした Ajax アプリケーションのサンプルをビルドします。また、DWR をポートレット・アプリケーションと統合する方法を説明しますが、DWR がどのような動作をしているかの詳細にまでは触れません。DWR ライブラリーについて詳しくは、プロジェクトの Web サイトや developerWorks のページを確認してください (詳細については、参考文献を参照してください)。ここで説明するアプリケーションをビルドするには、バージョン 1.3 以降の Java プラットフォームと JSR-168 に準拠したポータル環境が必要です。このコードを開発およびテストするために、IBM Rational Application Developer V6.0、Apache Jetspeed 2.0 ポータル、および Java 5.0 で構成された環境を使用しました。

始めるにあたって、ポートレットと Ajax 開発を熟知している必要があります。これらのトピックについてさらに学びたい場合は、以下の参考文献セクションを確認してください。DWR を含むサンプル・アプリケーションの完全なコードは、ダウンロード・セクションからダウンロードできます。

サンプルのポートレット間メッセージング・アプリケーションをビルドする

サンプル・アプリケーションには、Orders、Order Details、および Customer Details の 3 つのポートレットがあります。図 1 は、サンプル・アプリケーションを示しています。

図 1. サンプル・アプリケーション
Sample application

Orders ポートレットには、注文のリストがあります。ユーザーが注文番号をクリックすると、ポートレットが Order Details ポートレットと Customer Details ポートレットに注文番号を送信します。次に、これらのポートレットが、該当する注文と顧客の詳細を表示します。

開発環境をセットアップする

ポートレットを開発する前に、開発環境と DWR をセットアップする必要があります。私は、Java ポートレット開発のサポートが組み込まれている IBM Rational Application Developer V6.0 を使用しますが、どのような開発環境でもかまいません。それでは、次のステップに従って始めましょう。

  1. 新しい JSR-168 ポートレット・プロジェクトを作成します。プロジェクトに InterPortletMessaging という名前を付けますが、ポートレットはまだ作成しないでください。
  2. dwr.jar (バージョン 1.1。リンクについては、参考文献を参照してください) をダウンロードして、/WebContent//WEB-INF/lib ディレクトリー内のプロジェクトに追加します。
  3. web.xml を開いて、リスト 1 のコードを追加します。これで、DWR サーブレットがアプリケーションに追加されます。このサーブレットは、バックグラウンドで要求を処理して、応答をブラウザーに戻します。
    リスト 1. DWR サーブレット
    <servlet>
    
      <servlet-name>dwr-invoker</servlet-name>
      <display-name>DWR Servlet</display-name>
      <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
      <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
      </init-param>
    </servlet>
    
    <servlet-mapping>
      <servlet-name>dwr-invoker</servlet-name>
      <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
  4. リスト 2 のコードを使って、WEB-INF ディレクトリーに dwr.xml というファイルを作成します。これは、JavaScript で使用可能なクラスをコンテナーに伝える DWR 構成ファイルです。DWR はこの XML ファイルを読み取って、JavaScript コードを動的に生成し、Java クラスを JavaScript クラスで表します。これで、これらの Java クラスが提供する機能をブラウザーで使えるようになります。実際には、リスト 2 で参照されている Java クラスはまだ作成していませんが、すぐ後で作成します。
    リスト 2. dwr.xml
    <!DOCTYPE dwr PUBLIC
        "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
        "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
    
    <dwr>
      <allow>
        <create creator="new" javascript="MessagingBean">
          <param name="class" value="msg.MessagingBean"/>
        </create>
      </allow>
    </dwr>

これで、ポートレットで DWR を使用できるようになりました。ただし、サンプル・ポートレットを作成する前に、サンプル・アプリケーションのバックエンドの役割を果たす messaging Bean と mockup database Bean を作成する必要があります。

MockupDB と MessagingBean を作成する

リスト 3 に示されている MockupDB は、顧客からの注文のデータベースをシミュレートする singleton クラスです。すべての注文は、このクラスでハードコーディングされています。実際のアプリケーションはおそらくリレーショナル・データベース・システムを使用しますが、ここではこれで十分です。

リスト 3. MockupDB
package db;

import java.util.Hashtable;
import java.util.Map;

public class MockupDB {

  private static MockupDB instance=new MockupDB();

  private String[] orders=new String[4];
  private Map orderDetails=new Hashtable();
  private Map customerDetails=new Hashtable();

  private MockupDB()
  {
    String ordStart="ORD";
    orders[0]=ordStart+"000408015";
    orders[1]=ordStart+"001600023";
    orders[2]=ordStart+"000042000";
    orders[3]=ordStart+"011235813";

    orderDetails.put(orders[0],"1. WebSphere Everyplace Connection Manager<br/>"+
                     "2. WebSphere Portal");
    orderDetails.put(orders[1],"1. DB2 Universal Database<br/>2. DB2 Everyplace");
    orderDetails.put(orders[2],"1. Tivoli Access Manager for e-business <br/>2."+
                     "Tivoli Directory Integrator");
    orderDetails.put(orders[3],"1. IBM System z9<br/>2. IBM System p5 550 Express");

    customerDetails.put(orders[0],"<b>Systems and Technology Group</b><br/>"+
                        "Some Road<br/>Finland");
    customerDetails.put(orders[1],"<b>Global Financing</b><br/>Another Street"+
                        "<br/>Finland");
    customerDetails.put(orders[2],"<b>Software</b><br/>Yet Another Road"+
                        "<br/>Finland");
    customerDetails.put(orders[3],"<b>Global Services</b><br/>Still Another "+
                        "Street<br/>Finland");
  }
    
  public static MockupDB getInstance()
  {
    return instance;
  }
    
  public String[] getOrders()
  {
    return orders;
  }
    
  public String getOrderDetails(String orderNro)
  {
    return (String)orderDetails.get(orderNro);
  }

  public String getCustomerDetails(String orderNro)
  {
    return (String)customerDetails.get(orderNro);
  }
}

リスト 4 に示されている MessagingBean は、2 つのメソッドを持つ単純な POJO です。これらのメソッドは、注文番号を受け取って、それぞれ注文の詳細と顧客の詳細を戻します。MessagingBean は、MockupDB から詳細を取得します。

リスト 4. MessagingBean
package msg;

import javax.servlet.http.HttpSession;

import db.MockupDB;

public class MessagingBean {

  public MessagingBean()
  {        
  }
    
  public String getOrderDetails(String orderNumber,HttpSession httpSession)
  {
    String orderDetails=MockupDB.getInstance().getOrderDetails(orderNumber);
    httpSession.setAttribute("orderDetailsOrderNumber",orderNumber);
    httpSession.setAttribute("orderDetails",orderDetails);
    return orderDetails;
  }

  public String getCustomerDetails(String orderNumber,HttpSession httpSession)
  {
    String customerDetails=MockupDB.getInstance().getCustomerDetails(orderNumber);
    httpSession.setAttribute("customerDetailsOrderNumber",orderNumber);
    httpSession.setAttribute("customerDetails",customerDetails);
    return customerDetails;
  }
}

また、MessagingBean は、HttpSession に注文の詳細と顧客の詳細を追加します。

javaScriptFunctions.jsp

javaScriptFunctions.jsp は、DWR (engine.js) と動的に作成された MessagingBean.js ライブラリーから JavaScript ライブラリーをインポートします。MessagingBean.js は、dwr.xml (リスト 2) で紹介した Java Bean と同じ名前を使っていることに気づくでしょう。実際には、DWR が MessagingBean.js を生成します。DWR フレームワークは engine.js ライブラリーを使いますが、一般的には、開発者自身がこのライブラリーを直接使うことはありません。

リスト 5 で確認できるように、sendOrderNr() 関数は、リスト 4 で定義した MessagingBean 関数を呼び出します。DWR は、メソッド呼び出しに HttpSession を自動的に追加します。JavaScript 関数の最後のパラメーターは callback 関数です。この JSP は、次に作成するポートレット JSP に組み込まれています。

リスト 5. javaScriptFunctions.jsp
<%@ page contentType="text/html" 
import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>

<SCRIPT type="text/javascript"
	src='<%= renderResponse.encodeURL(renderRequest.getContextPath() +
	"/dwr/interface/MessagingBean.js") %>'> 
</SCRIPT>

<SCRIPT type="text/javascript"
	src='<%= renderResponse.encodeURL(renderRequest.getContextPath() + 
	"/dwr/engine.js") %>'> 
</SCRIPT>

<SCRIPT type="text/javascript">

function <portlet:namespace />sendOrderNr(orderNr)
{
document.getElementById("orderDetailsOrderNumber").innerHTML=orderNr;
document.getElementById("customerDetailsOrderNumber").innerHTML=orderNr;
MessagingBean.getOrderDetails(orderNr,<portlet:namespace />showOrderDetails);
MessagingBean.getCustomerDetails(orderNr,<portlet:namespace />showCustomerDetails);

return false;
}

function <portlet:namespace />showOrderDetails(orderDetails)
{
document.getElementById("orderDetails").innerHTML=orderDetails;
return false;
}

function <portlet:namespace />showCustomerDetails(customerDetails)
{
document.getElementById("customerDetails").innerHTML=customerDetails;
return false;
}
</SCRIPT>

ポートレットを作成する

バックエンド機能とプロキシー機能ができたので、ポートレット自体を開発できるようになりました。3 つのポートレットはすべて同じコードベースを使います。異なるのは、それぞれが使っている JSP の名前だけです。

  1. リスト 6 のコードを使用して新しいポートレットを作成して、Orders という名前を付けます。
    リスト 6. Orders.java
    package interportletmessagingusingajax;
    
    import java.io.*;
    
    import javax.portlet.*;
    
    public class Orders extends GenericPortlet {
    
      // JSP folder name
      public static final String JSP_FOLDER = "/interportletmessagingusingajax/jsp/";
    
      // JSP file name to be rendered on the view mode
      public static final String VIEW_JSP = "OrdersView";         
    
    
      public void init(PortletConfig config) throws PortletException{
        super.init(config);
      }
    
      public void doView(RenderRequest request, RenderResponse response) 
        throws PortletException, IOException {
        // Set the MIME type for the render response
        response.setContentType(request.getResponseContentType());
    
        // Invoke the JSP to render
        PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher( 
          getJspFilePath(request, VIEW_JSP));
        rd.include(request,response);
    
        //this is workaround for portletsession sharing between
        //servlets and portlets
        //see http://weblogs.java.net/blog/wholder/archive/2005/02/session_session.html
        //and http://mail-archives.apache.org/mod_mbox/portals-pluto-dev/200502.mbox/%3Ca
        //2519328f3ba1d1eddfc33c924b6805d@umich.edu%3E
        //
        PortletRequestDispatcher rd2 = getPortletContext().getRequestDispatcher("/dwr/");
        rd2.include(request, response);
    
      }
    
      private static String getJspFilePath(RenderRequest request, String jspFile) {
        String markup = request.getProperty("wps.markup");
        if( markup == null )
          markup = getMarkup(request.getResponseContentType());
        return JSP_FOLDER+markup+"/"+jspFile+"."+getJspExtension(markup);
      }
    	
      private static String getMarkup(String contentType) {
        if( "text/vnd.wap.wml".equals(contentType) )
          return "wml";
        return "html";
      }
    
      private static String getJspExtension(String markupName) {
        return "jsp";
      }
    }
  2. OrdersView.jsp を (interportletmessagingusingajax/jsp/html ディレクトリーに) 作成して開き、リスト 7 のコードを追加します。
    リスト 7. OrdersView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    <jsp:include page="javascriptFunctions.jsp" />
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Orders</H4>
    <table cellspacing="0" cellpadding="5" border="1">
    <% db.MockupDB database= db.MockupDB.getInstance();
    
    String[] orders=database.getOrders();
    for(int i=0;i<orders.length;i++)
    {
    %>
    <tr>
    
    <td><%="000000000"+String.valueOf(i+1) %></td>
    <td><a href="" onclick="return <portlet:namespace />sendOrderNr('<%=
      orders[i]%>');"><%=orders[i]%></a></td>
    </tr>
    <%
    }
     %>
    
    </table>
    </DIV>
  3. 2 番目のポートレットは OrderDetailsPortlet.java です。このポートレットではリスト 6 のコードを使って、VIEW_JSP 変数の値を OrdersDetailsPortletView.jsp に変更します。この JSP のコードはリスト 8 にあります。
    リスト 8. OrdersDetailsPortletView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Order details</H4>
    
    <table cellspacing="0" cellpadding="5" border="1">
    <tr>
    <th>Order number</th>
    <th>Order details</th>
    </tr>
    
    <tr>
    <%
    String orderDetailsOrderNumber=(String)renderRequest.getPortletSession().getAttribute(
      "orderDetailsOrderNumber",PortletSession.APPLICATION_SCOPE);
    String orderDetails=(String)renderRequest.getPortletSession().getAttribute(
      "orderDetails",PortletSession.APPLICATION_SCOPE);
    
    if(orderDetailsOrderNumber==null)
    {
    orderDetailsOrderNumber="";
    }
    
    if(orderDetails==null)
    {
    orderDetails="";
    }
    %>
    <td><div id="orderDetailsOrderNumber"><%=orderDetailsOrderNumber%>
    </div></td>
    <td><div id="orderDetails"><%=orderDetails%></div></td>
    </tr>
    
    
    </table>
    </DIV>
  4. 3 番目のポートレットは CustomerDetailsPortlet.java です。このポートレットにはリスト 6 のコードを使用して、VIEW_JSP 変数の値を CustomerDetailsPortletView.jsp に変更します。この JSP のコードはリスト 9 にあります。
    リスト 9. CustomerDetailsPortletView.jsp
    <%@ page contentType="text/html" 
    import="java.util.*,javax.portlet.*,interportletmessagingusingajax.*" %>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    
    <%
    %>
    
    <DIV style="margin: 6px">
    
    <H4 style="margin-bottom: 3px">Customer details</H4>
    <table cellspacing="0" cellpadding="5" border="1">
    <tr>
    <th>Order number</th>
    <th>Customer details</th>
    </tr>
    
    <tr>
    <%
    String customerDetailsOrderNumber=
      (String)renderRequest.getPortletSession().getAttribute(
      "customerDetailsOrderNumber",PortletSession.APPLICATION_SCOPE);
    String customerDetails=(String)renderRequest.getPortletSession().getAttribute(
      "customerDetails", PortletSession.APPLICATION_SCOPE);
    
    if(customerDetailsOrderNumber==null)
    {
    customerDetailsOrderNumber="";
    }
    
    if(customerDetails==null)
    {
    customerDetails="";
    }
    %>
    <td><div id="customerDetailsOrderNumber"><%=customerDetailsOrderNumber%>
    </div></td>
    <td><div id="customerDetails"><%=customerDetails%></div></td>
    </tr>
    
    </table>
    </DIV>

これでサンプル・アプリケーションの準備ができました。次は、ポートレットを WAR ファイルとしてパッケージにして、Apache Jetspeed ポータルでテストします。


サンプル・アプリケーションをテストする

このセクションでは、サンプル・アプリケーションの動作を確認します。最初に、ポートレット WAR を作成して、Jetspeed ポータルにインストールします。次に、ポートレットをポータルに追加して、動作を確認します。すべてを単一のページにビルドしますが、必要であれば複数のページに配置することができます。その場合も背後のメカニズムは機能します。

ポートレット・アプリケーションを Jetspeed にインストールする

ポートレット WAR ファイルを <Jetspeed install dir>/webapps/jetspeed/WEB-INF/deploy ディレクトリーにコピーして、WAR ファイルを Jetspeed にインストールします。すると、Jetspeed がポートレットを自動的にインストールします。これで、ポートレットを使うための準備ができました。

新規ページを Jetspeed ポータルに追加するには、次のステップを使用します。

  1. Jetspeed ポータルにアクセスして、管理者としてログインします。
  2. 図 2 に示すように、右側の隅にあるEdit アイコンをクリックして、Inter-Portlet Messaging という名前の新規ページを追加します。
    図 2. 新規ページを追加する
    Add new page
  3. Inter-Portlet Messaging ページを選択して、Edit アイコンをクリックします。次に、このページにポートレットを追加するには、Add a portlet アイコンをクリックします。OrdersOrder Details、およびCustomer Details の各ポートレットを選択して、Select portlets をクリックしてポータル・ページにポートレットを追加します。これが完了すると、作成したページは図 3 のようになります。
    図 3. ページ上のポートレット
    Portlets on the page

ポートレット

図 4 に示す Orders ポートレットには、注文がリストされています。

図 4. Orders ポートレット
Orders portlet

注文番号をクリックすると、他のポートレットに特定の注文の詳細が表示されます。Customer Details ポートレットには、図 5 に示すように顧客情報が表示されます。この情報は MockupDB から取得されます。

図 5. Customer Details ポートレット
Customer Details portlet

また、Order Details ポートレットには、図 6 で確認できるように、MockupDB から取得された情報が表示されます。

図 6. Order Details ポートレット
Order Details portlet

必要であれば、前に戻って、ポートレットをさらに別のページに追加することもできます。ポートレットの内容はユーザー・セッションに保管されるため、ポートレットを単一のページに配置する必要はないことがわかると思います。


まとめ

この記事では、Ajax を使ってポートレット間通信を行う方法を紹介しました。Ajax は、対話式の Web ページを開発するための非常に強力な手法です。また、Ajax 対応のポートレットでは、ポータルでよくありがちな、要求から応答までの遅延がなくなることで、ユーザー・エクスペリエンスが大幅に向上します。

この記事のサンプル・コードは、独自のアプリケーションを開発するための開始点として使うことができます。このコードは、DWR がどのようにして、Java プログラミング・モデルを Web ブラウザーでも使えるようにしているかも示しています。DWR を使うと、ブラウザーで JavaBeans を使うことができるかのように感じられます。DWR は、Ajax の詳細のほとんどすべてを見えなくすることで作業を単純化し、ユーザーが Ajax 開発の基本ではなく目先の作業に集中できるようにします。


ダウンロード

内容ファイル名サイズ
Source codej-ajaxportlet.war3MB

参考文献

学ぶために

  • Mastering Ajax」(Brett McLaughlin 著、developerWorks、2006 年) を読んで、Ajax プログラミングと概念を把握してください。
  • DWR: Easy Ajax for Java を読んで、パッケージの作成者による一連の参考資料を使って DWR を開始してください。
  • Ajax for Java developers: Ajax with Direct Web Remoting」(Philip McCarthy 著、developerWorks、2005 年 11 月) には、DWR を使って JavaBeans メソッドを直接 JavaScript コードに公開し、Ajax の大変な作業を自動化する方法が示されています。
  • Build and test JSR 168-compliant portlets with Apache Pluto (Mark Talbot と Kulvir Singh Bhogal 共著、developerWorks、2006 年 4 月) には、簡単なポートレットをビルド、コンパイル、パッケージ化して、Pluto にデプロイして JSR 168 に準拠しているかどうかテストする方法が示されています。
  • developerWorks Web development は、さまざまな Web ベースのソリューションを網羅した記事を専門に扱っています。
  • Stefan Hepper 著の「Comparing the JSR 168 Java Portlet Specification with the IBM Portlet API」(developerWorks、2003 年 12 月) を読んで、Java ポートレット開発についてさらに学んでください。

製品や技術を入手するために

  • Direct Web remoting をダウンロードしてください。これは、この記事で開発したアプリケーションを使用可能にするオープン・ソースの Java ライブラリーです。
  • Apache Jetspeed をダウンロードして、このポータルの詳細を調べてください。
  • Rational Application Developer for WebSphere Software V6.0 で、この開発環境の無料のトライアル・バージョンをダウンロードしてください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, WebSphere, Web development
ArticleID=212081
ArticleTitle=DWR が Ajax によるポートレット間メッセージングを簡単にする
publish-date=07142006