Component.info()の挙動とComponent.setResponsePage()の引数の関係

はじめに

 Component.info()という便利なメソッドが存在します。
 FeedbackPanelにメッセージを出すことができるので、ちょっとした実験に便利だったりします。
 で、これの挙動がComponent.setResponsePage()の引数で変わるんだけど、なんでだろう、というメモです。
 そもそもComponent.info()は、Component.setResponsePage()と組み合わせて使うことを、考えてないような気もしますが。

環境

事象の起きるソース

 ページ遷移にComponent.setResponsePage()をよく使われると思いますが、Component.setResponsePage()にはいくつかのオーバーロードがあります。
 本事象は、Component.setResponsePage()の引数をclassで指定するか、インスタンスで指定するかで挙動が変わるという物です。
 いかに「こんな感じ」というソース抜粋を載せます。

ソース(Java側。setResponsePageにclassを渡した場合)

 setResponsePageにclassを渡すケースのソースは以下のような感じ。

    public HomePage(final PageParameters parameters) {

        // Add the simplest type of label
        FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
        add(feedbackPanel);
        add(new Label("message", "If you see this message wicket is properly configured and running"));

        Form form = new Form("form"){
            private static final long serialVersionUID = 1L;

            protected void onSubmit() {
                info("feedback");
                setResponsePage(HomePage.class);
            }

        };
        add(form);
    }
ソース(Java側。setResponsePageにインスタンスを渡した場合)

 setResponsePageにインスタンスを渡すケースのソースは以下のような感じ。

    public HomePage(final PageParameters parameters) {

        // Add the simplest type of label
        FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
        add(feedbackPanel);
        add(new Label("message", "If you see this message wicket is properly configured and running"));

        Form form = new Form("form"){
            private static final long serialVersionUID = 1L;

            protected void onSubmit() {
                info("feedback");
                setResponsePage(new HomePage(null));
            }

        };
        add(form);
    }
ソース(HTML側)

 HTMLは、共通です。

<html>
    <head>
        <title>Wicket Quickstart Archetype Homepage</title>
    </head>
    <body>
        <strong>Wicket Quickstart Archetype Homepage</strong>
        <br/><br/>
        <span wicket:id="feedback">feedback</span>
        <span wicket:id="message">message will be here</span>
        <form wicket:id="form">
        <input type="submit" />
        </form>
    </body>
</html>

ボタンをクリックしたときの挙動

 以下にソースの違いによる挙動の違いを示します。

setResponsePageにclassを渡した場合

setResponsePageにインスタンスを渡した場合

なぜ挙動が違うのか?

 setResponsePage(final Class cls)は遷移先のURLはブックマーク可能なURLになり、setResponsePage(final Page page)はブックマーク不可能なURLになることに起因しています。
 ブックマーク可能なURLとブックマーク不可能なURLではレンダリングのタイミングが違うのです。
 以下に簡単に処理の流れを記載します。

setResponsePageにclassを渡した場合
  1. 人がブラウザのボタンをクリックする。
  2. RequestCycle.detach()によって、getSession().cleanupFeedbackMessages()が実行される。これによりメッセージが消える。
  3. いったんブラウザにレスポンスを返す。
  4. ブラウザからリクエストが来る。
  5. ページのレンダリングをする。この時点で既にメッセージが消えている。
  6. ページを返す。
setResponsePageにインスタンスを渡した場合
  1. 人がブラウザのボタンをクリックする。
  2. ページのレンダリングをし、ページをバッファする。
  3. RequestCycle.detach()によって、getSession().cleanupFeedbackMessages()が実行される。これによりメッセージが消えるが、すでにページはレンダリングされている。
  4. いったんブラウザにレスポンスを返す。
  5. ブラウザからリクエストが来る。
  6. 生成済みのページを返す。
追試してみるには?

 以下の箇所にブレークポイントを張ると動きがつかみやすいかと思います。
 一つ目は、WicketFilter.doGetの「Are we using REDIRECT_TO_BUFFER?」とコメントがある辺り。ブックマーク可能なページのほうはバッファを使わずにページを返却し、ブックマーク不可能なページはバッファを使っていることがわかります。

 二つ目は、FeedbackMessagesModel.getObject()の適当なところ。このメソッドは、レンダリング中に呼ばれます。

 三つ目は、RequestCycle.detach()内のgetSession().cleanupFeedbackMessages()が呼びされれる個所。二つ目のブレークポイントと、このブレークポイントのどちらで先に止まるか、というあたりで流れがわかるはず。

さいごに

 「ブックマーク可能なページと、ブックマーク不可能なページの相違で本件は生じている!」と言い切るにはちょっと調査は手抜きだったりもするのですが、何かの参考になるかもということで。