本文へジャンプ

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


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

XForms を Google Web Toolkit と統合する、第 3 回: GWT を使って XForms を作成する

ロック・スター志望者のための Web アプリケーションを作成する

Michael Galpin (mike.sr@gmail.com), Developer, Ludi Labs
Michael Galpin は、1998年以来、プロとして Java ソフトウェアを開発してきています。彼は現在、カリフォルニア州のマウンテンビューにある、起業したばかりの会社、Ludi Labs に勤務しています。彼は California Institute of Technology で数学の学位を取得しています。

概要: この 4 回シリーズでは、GWT (Google Web Toolkit) と XForms とを組み合わせて動的な Web アプリケーションを作成する方法を説明します。第 1 回では、それぞれの技術について解説し、両者が JavaScript という基盤とどのような関係を持っているかを説明しました。第 2 回では、2 つのページを持つ小さなアプリケーションを作成する方法を説明しました。1 つのページは、レコード会社が管理するアーティストのリストを GWT を使って表示し、もう 1 つのページは、ある特定のアーティストが録音したアルバムを XForms を使って表示しました。第 3 回では、同じページで GWT と XForms を使い、それぞれの技術と JavaScript との関係を活用し、JavaScript を使って GWT と XForms との間の対話動作を実現します。

日付:  2007年 10月 09日
レベル:  中級 この記事の原文:  英語
アクティビティー: 2235 ビュー
お気軽にご意見・ご感想をお寄せください: 


はじめに

この第 3 回では、第 2 回で作成したロック・スターのアプリケーションをリファクタリングを行います。このアプリケーションでは、レコード会社の幹部がアーティストとアーティストのアルバムを管理することができます。今回は第 2 回の機能は何も変更せず、GWT と XForms を混在させることで、その機能の実装を変更します。ここでは、GWT を既存の任意の Web ページに容易に導入できることを説明します。GWT 流の Ajax コールを使って動的にデータをロードし、GWT の JSNI を使って XForms モデルを動的に作成します。これによってページを単純化することができ、GWT の JSNI を使って動的に XForms コントロールを作成すると、さらに単純化することができます。GWT 要素を混在させることで、サーバー・サイドのコードを単純化できるだけではなく、最初のページを小さく作ることができ、ダウンロードや描画が高速になります。


前提条件

この記事では、GWT のバージョン 1.4 と Mozilla の XForms プラグイン 0.8 を使います (ダウンロード用のリンクは「参考文献」を参照)。Mozilla の XForms プラグインは、Mozilla ベースの Web ブラウザー (Firefox や Seamonkey など) であれば、どのブラウザーでも動作します。GWT には、Java™ 言語の知識と HTML や CSS などの Web 技術の知識が必要です。この記事では JavaScript も頻繁に使います。XForms は Model-View-Control のパラダイムを頻繁に使うため、このパラダイムに慣れておくと役に立ちます。これまでに XForms と GWT を経験したことがあると、もちろん助けになりますが、必須ではありません。


動的な XForms とは

これまでは、同じページにインライン化されたモデルのインスタンス・データを XForms がどう描画するかを見てきました。このモデル・データは動的でした。JSP スクリプトレットを使ってデータを照会してフィルタリングし、XML をページに書き込みました。今度は、この XForms のページをもっと動的なものにします。ページにインスタンス・データを書き込むのではなく、インスタンス・データをサーバーから非同期で取得し、それをページ上のモデルに動的に追加します。そして Ajax コールには GWT を使い、XForms モデルを変更するためには GWT の JSNI を使います。


XForms のページに GWT を追加する

ここでは、XForms によるアルバム・ページに対して GWT を使います。すると、既存の Web ページにどうやって GWT を追加するかという疑問が湧いてきます。これは非常に単純です。必要なことは、(GWT の) Java から JavaScript へのコンパイラーによって、コードから生成される JavaScript ライブラリーを含めることだけです。ライブラリーはモジュールごとに 1 つのファイルから成り、XForms のページに含めるには、リスト 1 に示すコード行を追加するだけです。


リスト 1. GWT をアルバムのページに追加する
                
<xhtml:script language="text/javascript" 
src="org.developerworks.rockstar.RockStarMain.nocache.js"></xhtml:script>

開発者の人たちは、ページに GWT を追加することがあまりにも容易なことに、よく驚かされます。これは、何といっても設計のおかげです。GWT に見られる例の大部分は「既成のものに頼らない」アプリケーション、つまり GWT を使ってゼロから作成されたアプリケーションです。実際には、レガシー・アプリケーションも最低限のものは使われており、GWT はどちらのアプリケーションにも便利なように設計されています。GWT のコードが、どれも単なる JavaScript であることを思い出してください。そう考えれば、これほど簡単であることも納得できます。これでページの中に GWT を組み込めたので、このページ用の GWT のコード (つまり JavaScript にコンパイルされる Java コード) を書き始めることができます。


Ajax を使ってアルバム・データをロードする: XForms データを操作するための JSNI

このシリーズの第 2 回では、GWT を使ってアーティストのリストをページにロードしましたが、これを非同期で行いました。言い換えると、ページを作成し、アーティストのリストに対して Ajax リクエストを行いました。今度は同じ方法を、アルバムに対して使います。そのため、GWT の Ajax を使ってアルバムをロードするためのサービスが必要になります。


リモート・サービスを作成する

まず、サービスのインターフェースを宣言します (リスト 2)。


リスト 2. アルバム・サービスのインターフェース
                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface AlbumService extends RemoteService{
     public Album[] getAlbumsForArtist(int artistId);
     public void addAlbum(Album newAlbum);
}

これは、このシリーズの第 2 回で作成したサービスと非常に似ています。これと同じように、非同期版のサービスも必要です (リスト 3)。


リスト 3. 非同期サービス・インターフェースの宣言
                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface AlbumServiceAsync {
     public void getAlbumsForArtist(int artistId, AsyncCallback callback);
     public void addAlbum(Album newAlbum, AsyncCallback callback);
}

最後に、このサービスのサーバー・サイドの実装が必要です。この実装は GWT の RemoteServiceServlet を継承し、クライアントがこのサービスを HTTP を使って呼び出せるようにします。これをリスト 4 に示します。


リスト 4. アルバム・サービスの実装
                
package org.developerworks.rockstar.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.developerworks.rockstar.client.Album;
import org.developerworks.rockstar.client.AlbumService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class AlbumServiceImpl extends RemoteServiceServlet implements AlbumService {

     private static final long serialVersionUID = -2706402745094297460L;
     private Map<Integer,List<Album>> albumCache;
     private AlbumDao dao;
     
     public AlbumServiceImpl(){
          this.dao = new AlbumFileDao();
          List<Album> allAlbums = this.dao.getAllAlbums();
          // initialize cache
          int size = allAlbums.size();
          this.albumCache = new HashMap<Integer, List<Album>>(size);
          for (Album album : allAlbums){
               int artistId = album.getArtistId();
               List<Album> albums = this.albumCache.get(artistId);
               if (albums == null){
                    albums = new ArrayList<Album>();
                    this.albumCache.put(artistId, albums);
               }
               albums.add(album);
          }
     }

     public void addAlbum(Album newAlbum) {
          int artistId = newAlbum.getArtistId();
          List<Album> albums = this.albumCache.get(artistId);
          if (albums == null){
               albums = new ArrayList<Album>();
               this.albumCache.put(artistId, albums);
          }
          albums.add(newAlbum);
          List<Album> all = this.getAllAlbums();
          this.dao.saveAlbums(all);
     }

     public Album[] getAlbumsForArtist(int artistId) {
          List<Album> albums = this.albumCache.get(artistId);
          if (albums == null){
               return null;
          }
          Album[] array = new Album[albums.size()];
          array = albums.toArray(array);
          return array;
     }
     
     private List<Album> getAllAlbums(){
          List<Album> allAlbums = new ArrayList<Album>();
          for (int artistId : this.albumCache.keySet()){
               List<Album> albums = this.albumCache.get(artistId);
               allAlbums.addAll(albums);
          }
          return allAlbums;
     }

}

この場合も、物理データの管理 (ファイルシステムからの取得や XML の構文解析など) を抽象化するために DAO (Data Access Object) パターンを使いました。これによって、XML ファイルをベースとした単純な実装を、もっと標準的なデータベース駆動の実装と容易に交換することができます。これで、新しいサービスを GWT コードから使えるようになりました。


GWT を使ってリモート・サービスを呼び出す

org.developerworks.rockstar.client パッケージの中にあるすべてのコードは JavaScript にコンパイルされ、リスト 1 のような JavaScript ライブラリーを含む、すべてのページで利用できるようになります。そこで、アルバム・ページを扱うための新しい Java クラスを作成します。このソース・コードをリスト 5 に示します。


リスト 5. AlbumLib クラス
                

package org.developerworks.rockstar.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;

public class AlbumLib {
     public void loadAlbums(int artistId){
          AlbumServiceAsync albumService = this.getAlbumService();
          AsyncCallback callback = new AsyncCallback(){

               public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
               }

               public void onSuccess(Object result) {
                    Album[] albums = (Album[]) result;
                    for (int i=0;i<albums.length;i++){
                         addAlbumToModel(albums[i]);
                    }
                    refreshXformsModel();
               }
               
          };
          albumService.getAlbumsForArtist(artistId, callback);
     }
     
     private AlbumServiceAsync getAlbumService(){
          AlbumServiceAsync albumService = (AlbumServiceAsync) 
		             GWT.create(AlbumService.class);
          ServiceDefTarget endpoint = (ServiceDefTarget) albumService;
          String moduleRelativeUrl = GWT.getModuleBaseURL() + "albumService";
          endpoint.setServiceEntryPoint(moduleRelativeUrl);
          return albumService;
     }
     
     private native void addAlbumToModel(Album album)/*-{
          var model = $doc.getElementById("albums");
          var instance = model.getInstanceDocument("albumData");
          var dataElement = instance.getElementsByTagName("Data")[0];
          // create the new album node
          var newAlbumElement = instance.createElement("Album");
          var titleElement = instance.createElment("Title");
          titleElement.appendChild(instance.createTextNode(album.getTitle()));
          newAlbumElement.appendChild(titleElement);
          var yearElement = instance.createElement("Year");
          yearElement.appendChild(instance.createTextNode(album.getYear()));
          newAlbumElement.appendChild(yearElement);
          dataElement.appendChild(newAlbumElement);
     }-*/;
     
     private native void refreshXformsModel()/*-{
          var model = $doc.getElementById("albums");
          model.rebuild();
          model.recalculate();
          model.refresh();
     }-*/;
}

この Java クラスでは多くのことが行われています。第 1 に、先ほど作成した AlbumService のリモート呼び出しを行うために使われる 2 つの Java メソッドがあります。これは、第 2 回での ArtistService の呼び出し方と非常に似ています。このコードには、サービスが非同期のリクエストに適切に応答する際に使われるコールバック関数が含まれています。この場合では、コールバックは他の 2 つのメソッド、addAlbumToModel()refreshXformsModel() を利用しています。

この 2 つのメソッドは、第 1 回で見た例と同じように、JavaScript のネイティブ・メソッドです。

addAlbumToModel() メソッドは、XForms モデルを表現する JavaScript オブジェクトにアクセスするので、このメソッドを使えば XML のインスタンス・データにアクセスすることができます。第 1 回ではこれを、JavaScript でおなじみのパラダイム、document.getElementById(...) を使って行う方法を説明しました。ここではこれを GWT から行っているため、JavaScript で暗黙的な文書オブジェクトではなく、$doc を使っていることに注意してください。$doc を参照できれば、おなじみの DOM メソッドを使って新しい Album を XML オブジェクトに追加することができます。addAlbumToModel メソッドは繰り返し呼び出され、サーバーから返されるすべてのアルバムを追加します。サーバーからのレスポンスに対する繰り返しの処理が終わると、次に refreshXformsModel() メソッドを呼び出します。繰り返しますが、これはネイティブのメソッドです。このメソッドは再度 XForms モデルにアクセスし、このオブジェクトの API を使って、このモデルにバインドされているコントロールを更新します。

最後に、ページがロードされた時に必ず GWT メソッドが呼び出されるようにする必要があります。そのためには、元々の Albums.jsp を変更します (リスト 6)。


リスト 6. JSP から GWT の JavaScript を呼び出す
                
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:ev="http://www.w3.org/2001/xml-events" 
xmlns:xforms="http://www.w3.org/2002/xforms" 
     xmlns:xhtml="http://www.w3.org/1999/xhtml" 
	 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xhtml:head>
        <xhtml:title>Albums</xhtml:title>
        <xhtml:script language="text/javascript"
		 src="org.developerworks.rockstar.RockStarMain.nocache.js">
		 </xhtml:script>
        <xforms:model id="albums" xmlns="http://www.w3.org/1999/xhtml" 
		xmlns:xforms="http://www.w3.org/2002/xforms">
            <xforms:instance id="albumData" xmlns=""/>
        </xforms:model>
    </xhtml:head>
    <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
         <xhtml:div id="albumList">
              <xforms:repeat id="repeatItem" 
			  nodeset="instance('albumData')/Data/Album"
			  xmlns="http://www.w3.org/1999/xhtml" 
			  xmlns:xforms="http://www.w3.org/2002/xforms">
                   <xhtml:div>
                        <xforms:output ref="Title" xmlns="http://ww.w3.org/1999/xhtml" 
xmlns:xforms="http://www.w3.org/2002/xforms">
                             <xforms:label 
							 xmlns:xforms="http://www.w3.org/2002/
							 xforms">Title:</xforms:label>
                        </xforms:output>
                        <xforms:output ref="Year" xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms">
                             <xforms:label 
							 xmlns:xforms="http://www.w3.org/2002/
							 xforms">Year:</xforms:label>
                        </xforms:output>
                   </xhtml:div>
              </xforms:repeat>
         </xhtml:div>
    </xhtml:body>
</xhtml:html>

これを見るとわかるように、ページの本体がロードされれば単純に GWT のメソッドを呼び出します。また、先ほど使用したスクリプトレットはありません。それでも、body 宣言の中に非常に小さなスクリプトレットがまだ残っています。このスクリプトレットは単純にリクエスト・パラメーター artistId を渡します。これで、コードの大部分は UI コントロールを作成するためのものになりました。次に、これを GWT を使ってプログラムでも行えることを説明します。


GWT の JSNI を使って XForms コントロールを作成する

ここまでは、GWT と JSNI を使って XForms モデルとインスタンス・データにアクセスするための方法を見てきました。これをさらに一歩進め、GWT と JSNI を使って XForms コントロールを動的に作成しましょう。まず、繰り返しによるコントロールの作成部分を JavaScript で置き換えます (リスト 7)。


リスト 7. GWT の JSNI から作成する動的な XForms コントロール
                

private native void createControls()/*-{
    var xfNs = "http://www.w3.org/2002/xforms";
     // get the container div
    var container = $doc.getElementById("albumList");
    
    var repeater = $doc.createElementNS(xfNs,"xforms:repeat");
    repeater.setAttribute("id", "repeatItem");
    repeater.setAttribute("nodeset", "instance('albumData')/Data/Album");
         
    var titleOut = $doc.createElementNS(xfNs, "xforms:output");
    titleOut.setAttribute("ref", "Title");
    var titleLabel = $doc.createElementNS(xfNs, "xforms:label");
    titleLabel.appendChild($doc.createTextNode("Title:"));
    titleOut.appendChild(titleLabel);
    repeater.appendChild(titleOut);
         
    var yearOut = $doc.createElementNS(xfNs, "xforms:output");
    yearOut.setAttribute("ref", "Year");
    var yearLabel = $doc.createElementNS(xfNs, "xforms:label");
    yearLabel.appendChild($doc.createTextNode("Year:"));
    yearOut.appendChild(yearLabel);
    repeater.appendChild(yearOut);
    
    container.appendChild(repeater);
}-*/;

これも、簡単な DOM プログラミングを使って、ネイティブの JavaScript を使う XForms コントロールを作成しているにすぎません。このコードが用意できれば、あとは本体がロードされたときに呼び出される loadAlbums() メソッドに、このコードを追加すればよいだけです。コードを追加すると JNSI コードはコントロールを作成し、アルバム・データを取得するリモート・サービスを呼び出します。また、アルバム・データを使ったプログラムにより XForms のモデル・インスタンス・データが作成されます。すると、この XForms モデルは更新され、バインドされたコントロールが新しいデータを表示します。JSP のボディーは、今や非常に単純になりました (リスト 8)。


リスト 8. XForms コントロールを持たない、単純化された JSP
                
    <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
         <xhtml:div id="albumList">
         </xhtml:div>
    </xhtml:body>
	

XForms の JSP は突如として、アーティストのリストを表示するための、GWT の HTML ページに非常に似たものになっています。すべての UI は、Java クラスから生成した JavaScript を使ってプログラムで作成されています。データは GWT の Ajax を使って取得されます。

まとめ

第 3 回では、JSP スクリプトレットに大きく依存してデータをインライン化していた XForms のページを、GWT に大きく依存する最小限のページに変換しました。GWT の Ajax 機構を使って、サーバーから非同期にデータをロードしました。次に GWT の JSNI 機能を使って、XForms のモデルの中にインスタンス・データを動的に作成しました。そして最後に、さらに JSNI を活用し、アルバム・データを表示するために使用するすべての XForms コントロールを、JSNI を使って動的に作成しました。第 4 回では、XForms コントロールを使って GWT の Ajax をオンデマンドで呼び出す方法について説明する予定です。



ダウンロード

内容ファイル名サイズダウンロード形式
Part 3 sample coderockstar3_src.zip14KBHTTP

ダウンロード形式について


参考文献

学ぶために

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

議論するために

著者について

Michael Galpin は、1998年以来、プロとして Java ソフトウェアを開発してきています。彼は現在、カリフォルニア州のマウンテンビューにある、起業したばかりの会社、Ludi Labs に勤務しています。彼は California Institute of Technology で数学の学位を取得しています。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


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=XML, Java technology
ArticleID=267150
ArticleTitle=XForms を Google Web Toolkit と統合する、第 3 回: GWT を使って XForms を作成する
publish-date=10092007
author1-email=mike.sr@gmail.com
author1-email-cc=ruterbo@us.ibm.com

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。