Wicket内蔵のajaxエンジンを「使っていない」サンプルを軽く触ってみる

はじめに

 内輪的には「え?今更」というネタなのですが、メモしておこうと思いつつ、ずっとメモしていなかったサンプルがあるので、メモ。
 どんなサンプルかと言いますと、Wicket内蔵のajaxエンジンを使っていないサンプルです。
 prototypeサンプルと便宜上呼びたいと思います。

環境

サンプルの所在

 apache-wicket-1.3.4.zip内の下記のフォルダに格納されております。
apache-wicket-1.3.4\jdk-1.5\wicket-examples\src\main\java\org\apache\wicket\examples\ajax\prototype

 サンプル集のindexのどの辺りに存在するかは、下図を見てください。

そもそもWicket内蔵エンジンの本体とは?

 「Wicket in Action」のP242によれば、org.apache.wicket.ajaxパッケージのwicket-ajax.jsがエンジンの実装とのこと。また、デバッグ時に使用されるwicket-ajax-debug.jsなんていうのもあります。
 レンダリング後のHTMLにこれらのJSが含まれている場合は、Wicketajaxエンジンを使っていると言って良さそうです。

prototypeサンプルのレンダリング

 prototypeサンプルを実行した際のHTMLの出力例を以下に載せます。wicket-ajax.js及びwicket-ajax-debug.jsを読み込んでないことが確認できます。
 余談ですが、ここで読み込んでいるprototype.jsは、apache-wicket-1.3.4\src\jdk-1.5\wicket-examples\src\main\webappに存在するようです。Wicket 1.3.4のサンプルで使用されているprototype.jsのバージョンは1.4.0とのこと。

 レンダリング結果が微妙に長いので、ajaxな部分のコアな部分を抜粋します。
 クリックイベントに応答して、なにやらやっていることが分かると思います。

	<p>Counting link using Ajax: <a onclick="new Ajax.Updater('counter', '?wicket:interface=:0:link::ILinkListener::', {method:'get'}); return false;" href="?wicket:interface=:0:link::ILinkListener::">Click me!</a></p>

<html>
<head>
<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/

var clientTimeVariable = new Date().getTime();

/*-->]]>*/</script>


	<title>Wicket Examples - Prototype.js / component render</title>
	<script src="../prototype.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="../style.css"/>
</head>
<body>
    <span>
    <div><a style="color: #E9601A" target="_top" href="../index.html"><img src="../logo.png"/></a><span>
  	<a href="?wicket:bookmarkablePage=:org.apache.wicket.examples.debug.InspectorPage&amp;pageId=0"><img src="resources/org.apache.wicket.examples.debug.InspectorBug/bug.png" valign="center" border="0"/></a>
  </span></div>      
      <div id="titleblock" style="font-size:larger;height:1.5em;vertical-align:center;">
        <div style="float:left;"><span>prototype</span></div>
	      <div style="float:right;padding-right:10px"><a target="sources" onclick="var w = window.open(href, 'sources', 'scrollbars=no,location=no,menuBar=no,resizable=yes,status=no,toolbar=no,width=800,height=600'); if(w.blur) w.focus(); return false;" href="?wicket:interface=:0:mainNavigation:sources::ILinkListener::">Source code</a></div>
    </div>
    <br/>
  </span>
	<p>Counting link using Ajax: <a onclick="new Ajax.Updater('counter', '?wicket:interface=:0:link::ILinkListener::', {method:'get'}); return false;" href="?wicket:interface=:0:link::ILinkListener::">Click me!</a></p>

	<!-- the wicket component is enclosed in a span tag with a separate markup ID attribute -->
	<!-- because Wicket returns the whole <span wicket:id="counter>XYZ</span> markup. The   -->
	<!-- updater only replaces the contents of the tags, not the tags itself. -->

	<p>Link was clicked <span id="counter"><span>0</span></span> times.</p>
<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/

window.defaultStatus='Server parsetime: 0.047s, Client parsetime: ' + (new Date().getTime() - clientTimeVariable)/1000 +  's';

/*-->]]>*/</script>


</body>
</html>

onclick発生時の通信内容

 onclick発生時は以下のような通信が行われます。GET時のパラメータはレンダリング後のHTMLに埋め込まれたものを使っている様子。
 レスポンスにWicket独自っぽい内容は無さそうですね。

Send: Return Code: 0x00000000
GET /wicket-examples/prototype/?wicket:interface=:0:link::ILinkListener:: HTTP/1.1
Accept: */*
Accept-Language: ja
x-prototype-version: 1.4.0
Referer: http://localhost:8080/wicket-examples/prototype/
x-requested-with: XMLHttpRequest
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: localhost:8080
Connection: Keep-Alive
Cookie: JSESSIONID=9F07577FFAE02B030C2C034AB2837F2F



Receive: Return Code: 0x00000000
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 14
Date: Sun, 07 Jun 2009 14:16:21 GMT

<span>1</span>

ソース(HTML側)

 サンプルの動きをざっと見たので、ソースの方へ。
 下にHTML側の実装を載せます。何事もなさ過ぎてびっくりな感じです。強いて言いますと、「今回のサンプルはベタにprototype.jsをここで読むんだー」という辺りが注目のポイントでしょうか。

<html>
<head>
	<title>Wicket Examples - Prototype.js / component render</title>
	<script type="text/javascript" src="prototype.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
    <span wicket:id="mainNavigation"/>
	<p>Counting link using Ajax: <a href="#" wicket:id="link">Click me!</a></p>

	<!-- the wicket component is enclosed in a span tag with a separate markup ID attribute -->
	<!-- because Wicket returns the whole <span wicket:id="counter>XYZ</span> markup. The   -->
	<!-- updater only replaces the contents of the tags, not the tags itself. -->

	<p>Link was clicked <span id="counter"><span wicket:id="counter">-100</span></span> times.</p>
</body>
</html>

ソース(Java側)

 Java側のソースは見るべきポイントがいくつかあるようです。
 まずは、getOnClickScriptをオーバーライドしていること。
 HTMLに出力するonClickの内容を自分で実装するにはこうするのですね。

/**
 * Alter the javascript 'onclick' event to emit the Ajax call and update the counter
 * label.
 */
protected String getOnClickScript(String url)
{
    return new AppendingStringBuffer("new Ajax.Updater('counter', '").append(
            urlFor(ILinkListener.INTERFACE))
            .append("', {method:'get'}); return false;").toString();
}

 次にonClickの実装方法。setRequestTargetメソッドを呼び出して、ComponentRequestTargetというクラスのインスタンス渡しています。
 setRequestTargetというメソッド名だけ読みますと「?」という感じですが、「オープンソース徹底活用WicketによるWebアプリケーション開発」のP258に下記の記述があり、それを踏まえると「なるほどー」といった感じです。

リクエスト・ターゲットはリクエスト・サイクルがレスポンスを生成するためのスタート地点となるオブジェクトです。

public void onClick()
{
	// Increment count
	count++;

	// The response should refresh the label displaying the counter.
	getRequestCycle().setRequestTarget(new ComponentRequestTarget(counter));
}

さいごに

 「onClick以外はどうするの?」など掘り下げるネタはあるのですが、今回はこの辺で。

 話は変わりますが、はてブで励ましてくれた方ありがとうございます。
 気になるwicketネタがあったら、ネガティブでもポジティブでも記録していきます。