japan.internet.comThe Internet & IT Network
Twitter
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2009年11月22日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
賛成
反対
どちらとも言えない
投票締切 11/30 12:00
デベロッパー コラム2006年9月12日 11:00
DevX
DevX japan.internet.com 編集部(japan.internet.com)メールホームrss
米国 WebMediaBrands が運営する、
企業向けアプリケーションの開発者向けの技術情報/サービスサイト。

Google Web Toolkit:現実的な開発に即したAJAX

海外海外internet.com発の記事

はじめに

 AJAXアプリケーションの開発は簡単なものではありません。というのも、AJAX(Asynchronous JavaScript and XML)の開発言語であるJavaScriptの全貌を把握している開発者はほとんどいないからです。さらに悪いことに、JavaScriptの実装はブラウザによって違いがあるため、互換性という厄介な問題もあります(「補足記事1 以前のWeb UIおよびAJAXのJavaScriptの弱点」を参照)。GmailとGoogle MapsによってAJAXの名を知らしめたGoogleが、この問題を解決するために世に送り出したのがGoogle Web Toolkit(GWT)です。

必要な環境

  • Google Web Toolkit
  • Apache Ant 1.6
  • Apache Tomcat
  • Java Standard Edition 1.4以降
  • Eclipse
補足記事1 以前のWeb UIとAJAXのJavaScriptの弱点
 ユーザーインターフェイスの開発に関して、デスクトップアプリケーションの開発者をうらやましく思った経験があるのではないでしょうか? 特にうらやましいのは、数々のコントロールと洗練されたイベントリスニングの枠組みを備えたJava Swingを利用している人々です。Swingでは、マウスのクリック、コンポーネント上でのマウスポインタの移動、マウスホイールの回転、コンポーネント上でのマウスホイールの回転などに応答できます。これだけの機能があれば、ブロードウェイミュージカルのように派手なアプリケーションを作成するのも簡単でしょう。
 一方、Web開発者が利用できるのは、いくつかの不恰好なHTMLコントロール、貧弱なサーブレット/JSP、薄っぺらなイベントモデル、そして最低限のIDEサポートです。ユーザーのさまざまな操作に応答するだけでもサーバーとのやりとりが発生するため、軽快に動作するインターフェイスはあきらめざるを得ません。Web開発者がせいぜい余興どまりのアプリケーションしか作成できないのも無理はないのです。
 また、サーブレット/JSP、Javaオブジェクト、DHTML、JavaScript、CSSの開発およびテストを統合的に行うことが期待される統合開発環境(IDE)でも、大抵の場合はぎこちない連携しか実現されてないということを考えると、Web開発者がどのようにして日々の開発作業をこなしているのか不思議に思うくらいです。
 AJAXは、ユーザーが指を動かすたびにページ全体をリロードするのではなく、データを小さなパケット単位で交換することによって、Webのユーザーインターフェイスの魅力を高め、Webページの応答性を高めるものとして期待されています。AJAXとは、JavaScript、HTML、CSS、XML、ブラウザのDocument Object Model(DOM)が調和して生まれた集合体です。この集合体は、XMLHttpRequestオブジェクト(実装によってはIFRAME)を介してやりとりを行います。また、このXMLHttpRequestオブジェクトはクライアントブラウザのJavaScriptとWebサーバーとの間でやり取りされるXMLの転送および操作を行いますが、ここにAJAXのアキレス腱とも呼べる弱点があります。
 もしもあなたが私の知る大半のJava開発者と同類の人であれば、おそらくJavaScriptを見ただけで顔をしかめるでしょうし、簡単な検証以上のことをJavaScriptで行うと考えただけでうんざりするはずです。開発者が概してJavaScriptを避けたがるのは、JavaScriptがコンポーネントやオブジェクトの設計指針を重んじていないからです。さらに悪いことに、各種のブラウザのJavaScriptの実装は不安定であり、そのおかげでJavaScriptのコードはいとも簡単に台無しになってしまう傾向があります。

Googleが推進するAJAX開発用のWeb Toolkit

 Googleは同社のアプリケーションであるGmailとGoogle MapsにAJAXを利用しています。Googleの開発者はおそらく喜んでJavaScriptを使用したわけではないでしょうが、それによってこの巨大検索エンジンの歩みが妨げられることはありませんでした。Googleが利用したのは、コンピュータの登場当初から広く使われてきた技術、つまり典型的なコンパイラでした。コンパイラは、開発者が自分たちに理解しやすい高レベルの言語で開発やコーディングを行えるようにする技術です。コンパイラにより、高レベル言語で書かれたコードが低レベル言語に変換されます。

 Googleのある小さな開発チームが、JavaをJavaScriptに変換するコンパイラを作成したことで、Googleの開発者は設計、開発、デバッグ、テストをJavaで行い、それをJavaScriptに変換することが可能になりました。Googleのモットー「Do No Evil(悪いことはしない)」に従い、チームはこのテクノロジをGoogle Web Toolkit(GWT)と名付けて開発者コミュニティに無償で共有することを決めました。

 GWTには、コンパイラのほかに、AJAX開発の苦労を軽減してくれる次のようなAPIおよびツールの一式が含まれています。

  • アプリケーションの起動ファイルを作成するスクリプト
  • Javaでの開発後、GWTによりJavaScriptにコンパイルできるUIウィジェットおよびレイアウトマネージャ
  • JavaScriptのクライアント/サーバー間のRPC通信を可能にするJavaコンポーネント
  • ブラウザの履歴スタックに対応する履歴関連のイベントおよび関数
  • Eclipse IDEでのデバッグを可能にするGWT環境
  • ユーザーインターフェイスおよびRPCのJavaコードをIE、Firefox、Mozilla、Safari、Operaと互換性のあるJavaScriptに変換するGWTコンパイラ

 本稿では、これらすべての機能を実際に利用するデモを紹介します。その過程で、GWTではまだ目新しい、Apache AntやTomcatと組み合わせてGWTを使う方法も学んでいきます。

サンプルアプリケーション「AJAX With Ease」

 実際に動かすために、まずはGoogle Web Toolkitをダウンロードしましょう。今回のチュートリアルでは、2006年7月10日にダウンロードした「gwt-windows-1.0.21.zip」を使っています。このファイルを展開すると、「gwt-windows-1.0.21」というフォルダの下にすべてのGWTファイルが用意されます。

 続いて、本稿で用いるソースコードをダウンロードして展開します。このzipファイルには、「AJAX With Ease」サンプルアプリケーションのソースコード、プロジェクトおよびアプリケーション作成スクリプト、さらにApache Antビルドファイルが含まれています。このアプリケーションには、GWTの主要な機能についてのサンプルが組み込まれています(「補足記事2 AJAX With Easeプロジェクトファイル」に、AJAX With Easeアプリケーションとプロジェクト作成スクリプトの詳細、さらにApache Tomcatの利用に必要な「build.xml」および「gwt-user-wo-javax.jar」ファイルについての説明を示します)。

 このアプリケーションをEclipseにインポートするには、Eclipseのメニューで[File]-[Import]-[Existing Projects Into Workspace]を順に選び、「ajaxwithease」フォルダの「ajaxwithease」プロジェクトを選んで[Finish]をクリックします。インポートが終わると、図1に示すようにEclipseでフォルダおよびファイルを参照できるようになります。

図1 Eclipseにインポートされた「AJAX With Ease」アプリケーション
図1 Eclipseにインポートされた「AJAX With Ease」アプリケーション

 今度はこのアプリケーションをデバッグモードで実行します。デバッグボタン(虫のアイコン)をクリックすると、図2に示すようにGWTホストブラウザが起動します。このホストブラウザはJVMフックによってEclipseに組み込まれており、このブラウザ内で開発中のWebアプリケーション全体を試すことができます。これでEclipseにブレークポイントを設定し、ホストブラウザでアプリケーションを実行して、ブレークポイントにヒットさせることができます。

図2 デバッグボタンによりGWTホストブラウザを起動
図2 デバッグボタンによりGWTホストブラウザを起動

 AJAX With Easeアプリケーションの使い方はきわめてシンプルです。[Styles]タブは、実行時にボタンにスタイルを適用して、ボタンの外観がどのように変わるかを示しています。また[RPC]タブは、テキストボックスに入力されたタイトルと名前を受け取って「hello」というメッセージを表示する方法を示しています。さらに[History]タブは、ユーザーがテキストボックスに何らかの値を入力して[Add to History]ボタンをクリックしたときに、URLにトークンを追加して、ユーザーがブラウザの[進む]および[戻る]ボタンをクリックしたときにのみ取得されるようにする方法を示しています。

 今のところGWTでは、Apache AntおよびTomcatをデプロイするための適切なサポートは行われていないません。GWTの「projectCreator.cmd」スクリプトによって作成されるAntファイルは、ほとんど実体のないスケルトンです。本稿のAJAX With Easeアプリケーションのビルドファイルには、JavaからJavaScriptへのコンパイルやJavaのコンパイルの実行、WARファイルの作成を行うために必要になる追加のタスクが含まれています。

 これらのタスクについては「補足記事2」で簡単に説明していますが、その他に、利用しているマシンに合わせて「build.properties」の内容を修正する必要があります。GWTのルートインストールフォルダを指すgwt.sdk.locationプロパティと、Tomcatの「webapps」フォルダを指すtomcat.webappsプロパティを次のように変更します。

# gwt install folder
gwt.sdk.location=c:/java/gwt/gwt-windows-1.0.21

# tomcat webapps directory
tomcat.webapps=c:/java/tomcat/Tomcat 5.5/webapps

 変更はこれで終わりです。AJAX With Easeアプリケーションをデプロイするには、ダウンロードファイルに含まれている「ajaxwithease-0.1.war」ファイルをTomcatの「webapps」フォルダにコピーするか、「build.xml」のdeployタスクを実行します。このdeployタスクは、init、prepare、gwt-compile、java-compile、javadoc、distの各タスクを長々と行った後、「ajaxwithease-0.1.war」ファイルをTomcatの「webapps」フォルダにコピーすることでデプロイを完了します。それでは、ブラウザからhttp://localhost:8080/ajaxwithease-0.1/Helloを参照して、このアプリケーションにアクセスしてみてください(Tomcatがマシンの8080番ポートを監視しているという前提です)。

補足記事2 AJAX With Easeプロジェクトファイル
 GWTには、Eclipseのプロジェクトといくつかの叩き台アプリケーションの作成に役立つ「applicationCreator.cmd」と「projectCreator.cmd」という2つのスクリプトファイルがバンドルされています。私が「AJAX With Ease」アプリケーションを作成するときには、次のようにしてこれらのスクリプトとパラメータを使用しました。
c:javagwtgwt-windows-1.0.21applicationCreator.cmd
 -eclipse ajaxwithease -ignore -out c:projectsajaxwithease
 com.techyatra.awe.client.Hello

c:javagwtgwt-windows-1.0.21projectCreator.cmd
 -eclipse ajaxwithease -ignore -out c:projectsajaxwithease
 上記のコマンドは、「ajaxWithEaseProjectCreator.cmd」ファイルと「ajaxWithEaseApplicationCreator.cmd」ファイルに記述されています。「ajaxWithEaseProjectCreator.cmd」ファイルによって、(ご想像の通り)各種ソースファイルを格納するための「src」フォルダ、.classpathファイル、.projectファイルが作成されました。なお、後ろの2つのファイルはEclipseのプロジェクトファイルです。Apache Antの「build.xml」ファイルの作成には-antオプションを使うこともできますが、このビルドファイルはほとんど中身のないものです。WARファイルの作成やWebサーバへのこのアプリケーションのデプロイを行うタスクはもちろん、JavaからJavaScriptへのコンパイルを実行するタスクさえ含まれていません。
 「ajaxWithEaseApplicationCreator.cmd」ファイルは、「hello」という叩き台アプリケーションを作成します。このアプリケーションには、クリックすると「Hello」と表示されるボタンとラベルを備えたHTMLページが含まれます。以下に、このスクリプトが作成するファイルおよびフォルダを示します。
  • 「Hello.java」および「Hello.html」ファイル
  • それぞれ「client」フォルダ、「public」フォルダの下に作成されます。GWTは、提供されたクラス名パラメータスクリプトの末端のフォルダが「client」フォルダであると想定します。「Hello.java」にはJavaScriptにコンパイルされるJavaコードが含まれており、「Hello.html」にはJavaコードと連携して動作するHTMLが含まれています。
  • 「hello-compile.cmd」スクリプトファイル
  • GWTのJava-to-JavaScriptコンパイラクラスを呼び出します。しかし、私はこのコンパイラクラスをApache Antから使っています。
  • 「hello-shell.cmd」スクリプトファイル
  • GWTホスト環境を起動します。しかし、IDEがなければこのGWT対応環境はほとんど役に立たないため、私はEclipseを使ってGWT環境を起動しています。
  • 「hello.launch」ファイル
  • このアプリケーションを起動するためにEclipseによって利用されます。
  • 「Hello.gwt.xml」モジュールファイル
  • エントリポイント、サーブレットパス、JavaScriptに変換されるJavaファイルを含むソースパスなど、このアプリケーションで用いるさまざまなGWT特有の設定を含むGWT用設定ファイルです(モジュールファイルの形式については、GoogleのGWTドキュメントを参照してください)。
 WebサーバにデプロイできるアプリケーションのWARファイルを作成するには、これらのファイルだけでは足りないことに気付くでしょう。Apache Tomcatのようなサーブレット/JSPサーバにデプロイできるアプリケーションを作成するには、「conf」「web」「lib」の各フォルダとその中身も必要になります。
 「lib」フォルダ内の「gwt-user-wo-javax.jar」ファイルに注意してください。これはGWTの「gwt-user.jar」からjavax.*パッケージを取り除いたものです。どうしてそんなことをする必要があるのでしょうか? その答えは後ほど出てきます。
 gwt-user-wo-javax.jarの説明
 WAR形式のマニフェストファイルやTomcat Webアプリケーションの設定ファイルが含まれる「conf」フォルダや「web」フォルダについての説明はいらないでしょうが、「lib」フォルダの「gwt-user-wo-javax.jar」には、ある程度の説明を必要とするちょっとしたごまかしが含まれています。
 AJAXとGWTとRPCを使用するアプリケーションをApache Tomcatにデプロイする場合には、GWTに付随する「gwt-user.jar」ファイルが必要になります。ただし、この「gwt-user.jar」にはjavax.*というJavaパッケージが含まれています。GWTのホストモードで実行するために、GWTはこのパッケージを必要とします。このパッケージはGWTの目的には役立ちますが、サーブレット/JSP仕様2.3の9.7.2項によれば、Tomcatはこの「gwt-user.jar」ファイルの読み込みを間違いなく拒否するため、Tomcatにデプロイされたアプリケーションは困った状況に陥ってしまいます。問題を引き起こしているのはjavax/servlet/Servlet.classです。「gwt-user.jar」がなければ、Tomcatではこのアプリケーションを起動できません。
 この問題をうまく回避するために現時点で行っている工夫は、WARファイルに含める前に「gwt-user.jar」からjavax.*ファイルを除外するというものです。「gwt-user-wo-javax.jar」は、こうした理由で「gwt-user.jar」からjavax.*を取り除いたものです。
 GWTの開発チームは、GWT Google Groupにおいて非公式ながらこのバグを認めています。そのため、今後のリリースで彼らがこのバグを修正してくれることは十分に考えられます。
 AJAX With Easeアプリケーションのbuild.xml
 GWTの「projectCreator.cmd」ファイルで-antパラメータを指定するとApache Antの叩き台ファイル「build.xml」が作成されますが、このファイルにはあまり中身がありません。GWTのJava-to-JavaScriptコンパイラクラスを呼び出すタスクや、Apache TomcatのようなWebサーバにデプロイするためのWebアプリケーションのWARファイルを作成するタスクさえ含まれておらず、叩き台としては少々物足りません。実用的なアプリケーションであれば、大抵はこうしたタスクを必要とするはずです。
 本稿のダウンロードサンプルには、AJAX With EaseアプリケーションのためのApache Antの「build.xml」と「build.properties」が含まれています。「build.xml」に記述されている次のようなタスクは、きっと皆さんのアプリケーション開発に大いに役立つことでしょう。
  • prepare
  • 「build」フォルダと「dist」フォルダを作成します(「build」フォルダは、JARファイルやWARファイルにパッケージ化される前のすべてのファイルを格納しておく場所です。また「dist」フォルダは、distタスクの実行中にJARファイルやWARファイルが置かれる場所です)。
  • java-compile
  • サーバ側のJavaコードをコンパイルします。
  • gwt-compile
  • GWTのcom.google.gwt.dev.GWTCompilerを使ってJavaコードをコンパイルして「bild」フォルダ内にJavaScriptを生成します(com.google.gwt.dev.GWTCompilerは、次に示すような、GWTの各種jarおよびAJAX With Easeのソースフォルダを含むgwt.compile.classpathを利用します)。
    ...
      <!-- GWT Compile Classpath -->
      <path id="gwt.compile.classpath">
        <pathelement path="${java.class.path}/"/>
        <pathelement location="${gwt.sdk.location}/gwt-user.jar"/>
        <pathelement
              location="${gwt.sdk.location}/gwt-dev-windows.jar"/>
        <pathelement location="${src.dir}"/>
      </path>
    
      <target name="gwt-compile" depends="static">
        <java classpathref="gwt.compile.classpath"
          classname="com.google.gwt.dev.GWTCompiler"
          fork="true">
          <arg value="-out"/>
          <arg value="${build.dir}"/>
          <arg value="${gwt.entrypoint.class}"/>
        </java>
      </target>
    ...
    
  • gwt-copy
  • GWTがgwt-compileタスクで作成したファイルを「build」フォルダにコピーします。
  • java-doc
  • Javaソースコードのすべてからドキュメントを作成します。
  • dist
  • WebアプリケーションのWARファイル(ajaxwithease-0.1.war)、ソースコード、ドキュメントのzipファイルを作成します。

GWTコンポーネントの詳細

 今度はGWTコンポーネントに親しむために、このアプリケーションの中身を覗いてみましょう。

HTMLホストページ:Hello.html

 GWTのAJAXでは、クライアントのアプリケーションロジックはすべて、ホストページと呼ばれる単独のHTMLページに記述されます。「public」フォルダ内の「Hello.html」ファイルは、このようなホストページの1つです。このファイルには、ユーザーとの対話のロジックとユーザーインターフェイスを実現するJavaScriptが含まれています。「Hello.html」ファイルは<script language="javascript" src="gwt.js"></script>タグを介してこのJavaScriptを取得し、<meta name=’gwt:module’ content=’com.techyatra.awe.Hello’>タグはそれをGWTモジュールにリンクさせます。

モジュール:Hello.gwt.xml

 「Hello.gwt.xml」ファイルには、GWTアプリケーションのロジック部分を実現するモジュールが含まれています。com.techyatra.aweにあるこの「Hello.gwt.xml」ファイルは、com.techyatra.awe.HelloというGWTモジュールを表しています。「Hello.gwt.xml」を含むフォルダは、AJAX With Easeアプリケーションのルートフォルダと見なされます。GWTでは、最終的に「client」フォルダおよび「public」フォルダに格納されるモジュールのJavaソースファイルおよびHTMLファイルを、このcom.techyatra.aweルートフォルダの下に置く必要があります。

 AJAX With Easeアプリケーションの「Hello.gwt.xml」ファイルには、このアプリケーションが継承するベースモジュール(com.google.gwt.user.User)と、RPC通信のためのサーブレットパスおよび実装クラス、さらにJavaのpublic static main(String[] args)関数に類似したインターフェイスを実装する叩き台クラス(EntryPoint)が含まれています。以下に、「Hello.gwt.xml」モジュールファイルのリストを示します。

<module>

  <!-- Inherit the core Web Toolkit-->
  <inherits name=’com.google.gwt.user.User’/>

  <!-- Ajax with Ease app entrypoint class-->
  <entry-point class=’com.techyatra.awe.client.Hello’/>

  <!-- GWT’s RPC Servlet path-->
  <servlet path=’/hello’
           class=’com.techyatra.awe.server.HelloServiceImpl’/>

</module>

EntryPoint

 ちょうどJavaアプリケーションがpublic static main(String [] arg)関数を持つクラスを必要とするように、GWTにはcom.google.gwt.core.client.EntryPointを実装するクラスが必要です。これはpublic void onModuleLoad()という関数だけを含む単純なインターフェイスです。

 AJAX With Easeアプリケーションの場合は、com.techyatra.awe.client.HelloクラスがこのEntryPointインターフェイスを実装しています。以下のリストに、「Hello.java」ファイルを使った実装を示します。

package com.techyatra.awe.client;
...
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Hello implements EntryPoint
{

    private HelloRPC helloRPC = new HelloRPC();
    private HelloCSS helloCSS = new HelloCSS();
    private HelloHistory helloHistory = new HelloHistory();
...
    /**
     * This is the entry point method.
     */
    public void onModuleLoad()
    {

        button.addClickListener(new ClickListener()
        {
            ...
        });

        tabs.add(helloCSS, "Styles");
        ...
        RootPanel.get("slot1").add(label);
        RootPanel.get("slot2").add(button);
        RootPanel.get("slot3").add(tabs);

    }
}

 GWTの場合、onModuleLoad()はアプリケーションのエントリポイントとしてだけでなく、事実上のコンストラクタとしても機能します。この関数は、コンパイルされたJavaScriptコードにおいて最初に実行されます。普通はonModuleLoad()関数にGWTのウィジェット、パネル、コンポジットといったユーザーインターフェイスコンポーネントを作成するコードを追加することになります。作成が終わって準備が整うと、これらのコンポーネントはRootPanelを介してHTMLページに追加されます。

RootPanel

 com.google.user.client.ui.RootPanelは、JavaコードをHTMLページに、ひいてはブラウザのwindowオブジェクトに関連付けるパイプの役割を果たします。GWTコンポーネントをブラウザのwindowオブジェクトに追加するには、次の2つの方法があります。

  1. GWTのJavaベースのレイアウトマネージャを使って完全なユーザーインターフェイスをコード内に作成し、RootPanel.get().add(your container object)を呼び出すことで、そのコンテナインスタンスをRootPanelに追加します。この方法では、インターフェイス全体はJavaコード内に存在し、実行時にJavaScriptによって生成されます。
  2. HTMLと動的なコードベースのインターフェイス生成を組み合わせます。この方法では、以降も引き続きWeb開発者が複雑なレイアウトとグラフィックを備えたWebページを作成することになります。ただし、コントロールはJavaコードによって動的に作成されるので、そのプレースホルダを指定します。最終的には、GWTのJavaコードによってこれらのプレースホルダに適切なコントロールが配置されます。

 上記1の方法、つまりJavaだけを使ってUIを作成するという方法は、グラフィックが少なくレイアウトがシンプルでGoogleに類似したインターフェイスのアプリケーションに向いています。一方、グラフィックやレイアウトを重視するようなアプリケーションには上記2の方法を検討するとよいでしょう。

 プレースホルダやスロットはHTMLファイル内に配置できます。これらのスロットに、「Hello.java」ファイルのRootPanel.get(slot name).add(your widget)を使って適切なコントロールを差し込みます。

Hello.html
...
<table align=center>
    <tr>
    <td id="slot1"></td><td id="slot2"></td>
    </tr>
</table>
...
Hello.java
...
    RootPanel.get("slot1").add(label);
    RootPanel.get("slot2").add(button);
...

 HTMLとコードを組み合わせる方法では、Web開発者が美しいレイアウトやグラフィックを担当し、Javaプログラマがより軽快なアプリケーションの実装を担当するという分担ができます。

UIコンポーネント:ウィジェットとパネル

 Java Swingと同様、GWTにもレイアウトマネージャとGUIコントロールが付随していますが、GWTではこれらをそれぞれ「パネル」と「ウィジェット」と呼びます。ウィジェットは、ユーザーが直接操作できるユーザーコントロールです。GWTウィジェットの例としてはButton、RadioButton、TextBox、TabBar、Tree、MenuBarなどがあります。これらのウィジェットはパネル内に配置され、ウィジェットの配置およびレイアウトはパネルによって決定されます。GWTのパネルにはHorizontalPanel、VerticalPanel、DockPanelなどがあります(GoogleのGWTドキュメントにはパネルおよびウィジェットの全リストがあります)。

 こうしたパネルおよびウィジェットの使い方や動作もまたJava SwingのGUIコンポーネントに似ています。これらのコンポーネントはプロパティの設定および取得を行うメソッドを持ち、通常のキーおよびマウス操作のイベントを扱うためのイベントリスナモデルをサポートしています。次のコードは「Hello.java」クラスの一部であり、簡単なGWTボタンを生成したうえでオーバライドし、クリックリスナを提供します。

...
public class Hello implements EntryPoint
{
  final Button button = new Button("Hello");
  ...
  public void onModuleLoad()
  {
    button.addClickListener(new ClickListener()
    {
      public void onClick(Widget sender)
      {
        ...
      }
    });
  }
  ...
}

 ウィジェットとパネルは便利なものですが、複雑なユーザーインターフェイスを作成するにはパッケージ化と、これらのインターフェイスに視覚的な装飾を施す機能が必要です。それでは、続いてコンポジットとカスケーディングスタイルシート(Cascading Style Sheets:CSS)について説明しましょう。

コンポジット

 GWTでは、ウィジェットおよびパネルのグループを結合して、コンポジットと呼ばれる独立したウィジェットを新たに作成できます。次のリストは、ボタンとパネルを結合してHelloCSSという便利で独立したコンポジットを作成する方法を示しています。

package com.techyatra.awe.client;

...
public class HelloCSS extends Composite
{
    final Button buttonCSS = new Button("Apply Style");
    final VerticalPanel panel = new VerticalPanel();

    public HelloCSS()
    {
        buttonCSS.addClickListener(new ClickListener()
            ...
            buttonCSS.addStyleName("awe-button");
            ...
        );
        panel.setHorizontalAlignment(panel.ALIGN_CENTER);
        panel.add(buttonCSS);
        setWidget(panel);
    }

}

 このHelloCSSウィジェットは「Hello.java」のルートパネルに配置されます。事実、AJAX With Easeアプリケーションはロジック部の機能をHelloCSS、HelloRPC、HelloHistoryの各ウィジェットにカプセル化しています。

カスケーディングスタイルシート

 GWTの大きな特徴は、カスケーディングスタイルシートを実際に採り入れていることです。すべてのウィジェットおよびパネルは、自由に変更できるデフォルトのCSSスタイルを持っています(例えば、gwt-Button{}を使った装飾可能なボタンウィジェットなど)。またaddStyleName(String)メソッドおよびremoveStyleName(String)メソッドを使ってGWTのJavaコードに独自のスタイルを追加したり削除することもできます。こうしたスタイルを.cssファイルに定義しておき、HTMLホストページでHTMLタグ<link>を使ってこれらを参照します。

 以下に、「ajaxwithease.css」ファイルの内容を示します。このファイルには、先ほど示したHelloCSSコンポジットのボタンに利用されていたAJAX With Easeアプリケーション固有のawe-buttonスタイルが含まれています。

...
.gwt-CheckBox {
    font-size: smaller;
}

...
.awe-button
{
    color:#0000FF;
    font-family:’trebuchet ms’,helvetica,sans-serif;
    font-size:84%;
    font-weight:bold;
    background-color:#fed;
}
...

 この「ajaxwithease.css」ファイルには、GWTのデフォルトのスタイルも含まれています。というのも、奇妙なことに「applicationCreator.cmd」ファイルはGWTのデフォルトスタイルを含む.cssファイルを作成しないためです。

 これでクライアント(ブラウザ+HTML/JavaScript)のほうは一段落したので、次はWebサーバーと通信してデータを取得し、ユーザーイベントに応答する必要があります。かつてのサーブレット/JSP開発では、この処理はサーバーとのやりとりを行ってページ全体をリロードすることを意味していました。AJAXの最大の利点はそうしたページ全体のリロードが必要なく、GWTのRPC基盤によってサーバーとの通信が容易になることです。

GWTのRPCに注目する

 図3は、AJAX With EaseアプリケーションがGWTのRPCをどのように利用しているかを示しています。

図3 GWTのRPCを利用した「AJAX With Ease」アプリケーション
図3 GWTのRPCを利用した「AJAX With Ease」アプリケーション

 では、それぞれのRPCについて説明しましょう。

  • Remote Serviceインターフェイス
  • クライアントフォルダにある「HelloService.java」はGWTのRemoteServiceを拡張しており、GWTのRPC基盤によって有効にする必要があるインターフェイスを表しています。
  • Remote Service実装クラス
  • 「server」フォルダにある「HelloServiceImpl.java」はHelloServiceに定義されているリモートインターフェイスを実装し、GWTのRemoteServiceServletを拡張しています。さらにRemoteServiceServletHttpServletを拡張したものです。つまり、HelloServiceImplはクライアントの要求(ブラウザ+HTML/JavaScript)に応答するサーブレットです。またHelloServiceImplはモジュール設定ファイルhello.gwt.xmlでも参照されており、その中でサーブレットパス「/hello」にマッピングされています。
  • 非同期コールバックインターフェイス
  • 「client」フォルダにあるHelloServiceAsyncは非同期のコールバックインターフェイスです。このクラスの名前は「Async」で始まるサービスインターフェイスのクラス名でなければなりません。ただし、このインターフェイスを実装する必要はありません。GWT側で実装されるためです。
    GWTのRPC通信における特異な点の1つは、それが非同期で行われることです。つまり、クライアントはサーバーを呼び出してもサーバーからすぐに応答が返ってくるのを待つ必要はありません。サーバーはデータが準備できた時点でクライアントに再接続し、その応答データをクライアントに提供します。
  • シリアライズ可能な型オブジェクト
  • 「Person.java」はGWTでシリアライズ可能な値オブジェクトです。このオブジェクトはhello()関数によってパラメータとして渡されます。クライアントとサーバーとの間でやりとりされるこの値オブジェクトを使うために、何か特別なことを行う必要はありません。GWTはこのパラメータのシリアライズ化およびデシリアライズ化の処理を行い、基本データ型の値および所与のカスタムJavaオブジェクトの値を返します。これらのカスタムオブジェクトはGWTのIsSerialiazableインターフェイスを実装しているので、これらのオブジェクトを定義するときにはGoogleのGWTドキュメントに記されたいくつかのルールに従います。このPersonオブジェクトが変わっているのは、クライアント側のJavaScriptとサーバー側のJavaバイトコードで使われている点です。
  • HelloConstants
  • このクラスはGWTが必要とするものではなく、EclipseのGWT Hosted Modeでアプリケーションのデバッグを行うときや、Apache TomcatのようなWebサービスにアプリケーションをデプロイするときのための必要悪です。このクラスはサーブレットパスを指す定数HELLO_SERVICE_URLを定義します。アプリケーションのデバッグ時には、GWT対応環境が想定しているようにHELLO_SERVICE_URLを/helloに設定する行を使う(非コメント化する)必要があります。ただし、WebサーバーにデプロイするWARファイルをビルドする準備ができたときは、実行時にHELLO_SERVICE_URLの設定行を、Webサーバーにデプロイしたときのhttp://localhost:8080/ajaxwithease-0.1/helloと等しい値に設定する(非コメント化する)必要があります。
    WARファイルのWebサーバーへのデプロイに加えて、次のように「web.xml」へのサーブレットのマッピングの追加も必要です。
    ...
      <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>
          com.techyatra.awe.server.HelloServiceImpl
        </servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
      </servlet-mapping>
    ...
    
  • HelloRPC
  • サービスHelloServiceを利用するコンポジットウィジェットです。このウィジェットはまずHelloServiceのサービスエンドポイントを取得し、続いてエンドポイントのエントリポイントがHelloServiceImplのサーブレットパスURLに設定されます。AsyncCallbackのインスタンスが作成され、helloService.hello()関数の呼び出し時にパラメータとして渡されます。AsyncCallbackonSuccessおよびonFailureはAJAX With Easeアプリケーション特有の処理を行うため、次のようにオーバライドされています。
    package com.techyatra.awe.client;
    ...
    public class HelloRPC extends Composite
    {
        ...
        HelloServiceAsync helloService = (HelloServiceAsync)
                          GWT.create(HelloService.class);
    
        ServiceDefTarget endpoint = (ServiceDefTarget)
                          helloService;
    
        public HelloRPC()
        {
            endpoint.setServiceEntryPoint
                (HelloConstants.HELLO_SERVICE_URL);
    
            ...
            AsyncCallback callback =  new AsyncCallback()
            {
                public void onSuccess(Object result)
                {
                    labelRPC.setText((String) result);
                }
    
                public void onFailure(Throwable caught)
                {
                    errorMessage.setHTML(caught.getMessage());
                }
            };
            helloService.hello(
                new Person(textTitle.getText(),
                textName.getText()), callback);
            }
            ...
        }
    }
    
    サーバーは処理を終えてデータを返す準備が整うと、AsyncCallbackに頼ってクライアントへのコールバックとonSuccess()メソッドの呼び出しを行います。サーバーによって投げられた例外はonFailure()メソッドが受けます。

 これでアプリケーションには立派なインターフェイスと高速なデータ検索機能が備わりましたが、履歴機能についてはどうでしょうか? GWTを使えば、履歴に対応させることができます。

あるべき履歴機能

 AJAXベースのアプリケーションを利用したときに出る大きな不満の1つは、ブラウザの戻るボタンが持っている機能が失われがちなことです。GWTの場合、履歴の機能が失われることはありません。GWTにはアプリケーションがブラウザの「戻る」および「進む」イベントに応答するためのフックが用意されています。

 次の「HelloHistory.java」のコードは、GWTのHistoryListenerインターフェイスを実装しているHelloHistoryというコンポジットウィジェットを示しています。

package com.techyatra.awe.client;

...

public class HelloHistory extends Composite
    implements HistoryListener
{
    public HelloHistory()
    {
        ...
        History.newItem(textHistory.getText());
        ...
        History.addHistoryListener(this);
    }

    public void onHistoryChanged(String historyToken)
    {
        String token = History.getToken();
        if (token != null)
        {
            textHistory.setText(token);
        }
    }
}

 アプリケーションのユーザーによってブラウザの[戻る]および[進む]ボタンが押された場合は、onHistoryChanged()メソッドの中でそれらの操作に応答できます。履歴の追跡にはトークンを用います。適当なところで履歴にトークンを追加し、これらのトークンを頼ってonHistoryChanged()関数内で適切な処理を実行します。

新たなアプリケーションプラットフォーム?

 GoogleがGWTで成し得た成果により、Windowsオペレーティングシステムに頼らずに、ファットクライアントと同等の機能を持つWebアプリケーションを開発することが可能になりました。プラットフォームの新たな領域が開拓されたと言えるのではないでしょうか。

著者紹介

Gautam Shah(Gautam Shah)
政府機関どうしの情報共有を可能にするソリューションなど、大規模で複雑なアプリケーションの開発に10年間にわたって従事。J2EE、.NET、オープンソースソリューションのほか、BizTalk、WebMethods、WebSphere Business Integration Serverのような各種統合プラットフォームに関する幅広い専門知識を持つ。
Graphic Design Forum
【Graphic Design Forum】
流動的媒体と静的媒体に関する見解(11月18日)
「IT の耳」
「IT の耳」
【書評】『Hyper-V スタートアップバイブル』――仮想化についてのすぐれた解説書(11月20日)
百式のネットビジネス研究
百式のネットビジネス研究
世界でもっともパワフルな iPod のスピーカー「Wall of Sound」(11月20日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(11月19日)
海外ソーシャルウェブに学ぶ成功の秘訣
海外ソーシャルウェブに学ぶ成功の秘訣
ゲーム業界を襲う世界的な激震。ソーシャルゲーム急成長のインパクト(11月19日)
今さら聞けない初歩からのアクセス解析
今さら聞けない初歩からのアクセス解析
サイトリニューアル前のアクセス解析活用法(11月19日)
成約率、反応率を上げる Web 文章術
成約率、反応率を上げる Web 文章術
文章力を磨き、キャッシュを生み出す Web サイト に(11月19日)
「Webからの脅威」―その傾向と最新対策
「Webからの脅威」―その傾向と最新対策
新たな対策技術:スパムフィルタリングと E-mail レピュテーション(11月18日)
ROI向上のための戦略的WebPR
ROI向上のための戦略的WebPR
「戦略的 WebPR」のしかけ方〜WebPR の効果測定手法とは〜(11月18日)
スマートにソーシャルウェブを構築しよう
スマートにソーシャルウェブを構築しよう
社員力を生かすソーシャルメディアポリシー(11月17日)
DevX
DevX
Erlangを使った並列処理プログラムの作成(11月17日)
Copyright 2009 Japan Internet.com K.K. All Rights Reserved.http://www.internet.com/