GAE for Javaのサンプルソースの解析

プロジェクトを新規作成したときのサンプルソースをちょっと解析してみたので簡単に解説。
といってもまだドキュメントをちゃんと読んでないので、あくまでソースコードを解析してみての個人的な予想。
まずサンプルアプリケーションは次のような画面で、ボタンをクリックするとサーバーから情報を取得してきて、それをダイアログ表示するというシンプルなもの。

ただこのボタンをクリックしてからダイアログ表示をするのにページ遷移は行われないので、非同期通信が行われていると思われます。

画面

まずこの画面の実体だが、「Sample」という名前でプロジェクトを作成し、パッケージを「ex」としたとすると、プロジェクト直下のwarフォルダにあるSample.htmlというファイルがそれだ。
このhtmlを開いて、テキストフィールドとボタンを探すも見当たらず。それっぽい箇所はこんな風になっている。

<table align="center">
  <tr>
    <td colspan="2" style="font-weight:bold;">Please enter your name:</td>        
  </tr>
  <tr>
    <td id="nameFieldContainer"></td>
    <td id="sendButtonContainer"></td>
  </tr>
</table>

というわけでどこかでこの「nameFieldContainer」の内部にテキストフィールドを、「sendButtonContainer」の内部にボタンを設定している箇所があるはずなのでそれを探さないと。

エントリーポイント

それはclientパッケージの中のSample.javaというファイルにありました。
onModuleLoadというメソッドのコメントには

This is the entry point method.

とあり、このメソッドがエントリーポイントとなるようです。
で、このメソッドを見てみると、色々初期化が行われています。

public void onModuleLoad() {
    final Button sendButton = new Button("Send");
    final TextBox nameField = new TextBox();
    nameField.setText("GWT User");

    sendButton.addStyleName("sendButton");

    RootPanel.get("nameFieldContainer").add(nameField);
    RootPanel.get("sendButtonContainer").add(sendButton);

とあり、まさにここでテキストフィールドとボタンをtdタグの内部に設定するように書かれていました。
他にも、

    final DialogBox dialogBox = new DialogBox();
    dialogBox.setText("Remote Procedure Call");
    ・・・略・・・

というようにダイアログが宣言されていたり、

    MyHandler handler = new MyHandler();
    sendButton.addClickHandler(handler);

というように、SendボタンがクリックされたらMyHandlerクラスが実行されるようにイベント登録がなされています。

イベントハンドラ

そのMyHandlerクラスですが、Sample.javaのインナークラスとして定義されています。

class MyHandler implements ClickHandler, KeyUpHandler {
    public void onClick(ClickEvent event) {
        sendNameToServer();
    }

    private void sendNameToServer() {
        ・・・略・・・

        String textToServer = nameField.getText();

        greetingService.greetServer(textToServer, new AsyncCallback<String>() {
            public void onFailure(Throwable caught) {
                ・・・略・・・
            }

            public void onSuccess(String result) {
                dialogBox.setText("Remote Procedure Call");
                serverResponseLabel.removeStyleName("serverResponseLabelError");
                serverResponseLabel.setHTML(result);
                dialogBox.center();
                closeButton.setFocus(true);
            }
        });
    }
}

ま、大体分かると思います。
なお、greetingServiceというインスタンスはこのクラスのメンバ変数として宣言されています。

private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

サーバーサイドロジック

このGreetingServiceというクラスは同じclientパッケージの中にあります。

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
    String greetServer(String name);
}

おそらくRemoteServiceRelativePathアノテーションの引数に指定した文字列がリクエストパスになるのだと思われます。
web.xmlには、

  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>ex.server.GreetingServiceImpl</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/sample/greet</url-pattern>
  </servlet-mapping>

と設定されており、greetというパスでHTTPリクエストがあると、ex.server.GreetingServiceImplクラスが呼び出されるように設定されています。
GreetingServiceImplクラスはさきほどのGreetingServiceを実装しています。

@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {

    public String greetServer(String input) {
        String serverInfo = getServletContext().getServerInfo();
        String userAgent = getThreadLocalRequest().getHeader("User-Agent");
        return "Hello, " + input + "!<br><br>I am running " + serverInfo
				+ ".<br><br>It looks like you are using:<br>" + userAgent;
    }
}

・・・とまぁ大体こんな感じです。一応サンプルコードは大体分かりました。
ただ今回のコードは従来ならjsp & javascriptjQueryなどを使って)でやっていたはずです。
GAEではそのようなやり方がそもそも禁止されていてこのようなコードになっているのか、そうではなく、もしできるのであればどういうときにJavaのコードを使って、どういうときにjsp & javascriptでやるのか、その辺の使い分けなんかについてこれから勉強していこうと思います。

追記

これ、GAEの解説というか、単にGWT(http://code.google.com/intl/ja/webtoolkit/gettingstarted.html)の解説ですね。。
アプリケーション作成時に「Use Google Web Toolkit」のチェックを外すと、いわゆるサーブレットプログラミングのサンプルが出来上がります。