Wicket内蔵のajaxエンジンを「使っていない」サンプルを軽く触ってみる
はじめに
内輪的には「え?今更」というネタなのですが、メモしておこうと思いつつ、ずっとメモしていなかったサンプルがあるので、メモ。
どんなサンプルかと言いますと、Wicket内蔵のajaxエンジンを使っていないサンプルです。
prototypeサンプルと便宜上呼びたいと思います。
環境
- Wicket 1.3.4
サンプルの所在
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が含まれている場合は、Wicketのajaxエンジンを使っていると言って良さそうです。
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&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)); }