原文著者: Authors: Andrea Del Bene, Martin Grigorov, Carsten Hufe, Christian Kroemer, Daniel Bartl, Paul Borș, Tobias Soloschenko, Igor Vaynberg , Joachim Rohde
訳注は で示します。
訳語集
- ページ部品
- org.apache.wicket.Component 原文では単に component
7. ページ部品のライフサイクル
アプレットやサーブレットと同様にWicketのページ部品はその存在期間中に幾つかの段階が存在します。この章ではその段階それぞれについで分析し、ページ部品の段階が切り替わった時に実行される(ほとんど全ての)フックメソッドの作り方を学びます。
7.1. ページ部品のライフサイクル段階
ページ部品の生涯には以下の3つの基本的段階があります:
- 初期化(initialization)
- Wicketによりページ部品が生成され、描写前の準備が行われます。
- 描写中(Rendering)
- この段階でWicketはページ部品のマークアップを生成します。(例えばMarkupContainerのような)子となるページ部品が含まれていた場合は、自身の描写に先立ってにそれら(子となるページ部品)の描写が完了するのを待たなくてはなりません。
- 除去中(Removing)
- この段階はページ部品が明示的にページ部品の木構造から除去された時、例えば親となるページ部品がそのページ部品に対して`remove(component)`を呼び出したとかいった時に発生します。この段階は随意のもので(開発者がremoveしなきゃ呼ばれないよという意味です)、ページそのものについては発生することはありません。
以下がページ部品のライフサイクル段階の状態遷移図になります。
ページ部品は一度除去された後、再びコンテナ(親あるいは他のページ部品)に追加することができますが、初期化段階が再び発生することはありません。
ページ部品のライフサイクルに関するより詳細な説明はComponent
クラスのJavaDocにあります。JavaDocの説明はまだ説明していない高度な内容を含んでいるため、この章では混乱を避けるために、後の章で説明する詳細な部分については省略しています。今は上に説明した簡略化されたライフサイクルについてだけ考えてください。
7.2. 各ライフサイクル段階に対応するフックメソッド
Component
クラスにはそれぞれのライフサイクル段階における振る舞いをカスタマイズするための、オーバライド可能なたくさんのフックメソッドがあります。以下の表ではそれらのメソッドを実行されるライフサイクル段階別にグループ化したものになります(同じグループのものは実行順に並べられています):
段階 | 実行されるメソッド |
---|---|
初期化 | onInitialize |
描写中 | onConfigure, onBeforeRender, onRender, onComponentTag, onComponentTagBody, onAfterRenderChildren, onAfterRender |
除去中 | onRemove |
ではそれぞれの段階と実行されるフックメソッドについて詳しく見ていきましょう。
7.3. 初期化(Initialization stage)
この段階はページ部品のライフサイクルの一番最初に実行されます。初期化段階のページ部品はページ全体の木構造に既に組み込まれているため、安全にgetParent()
やgetPage()
のようなメソッドによって親となるページ部品やページそのものにアクセスすることが可能です。この段階で呼び出されるメソッドはonInitialize()
のみです。このメソッドは任意の初期化処理を実行することができる特殊化されたコンストラクタとでも呼ぶべきものです。
またonInitialize
は一般的なコンストラクタと同様に、オーバーライドした場合には親クラスのsuper.onInitializeをそのメソッド内で呼び出さなくてはなりません。(普通は場合は一番最初に呼び出ます)
7.4. 描写中(Rendering stage)
この段階はページ部品がWicketによって描写されるたび、典型的にはページがリクエストされた時やAJAXで更新された時に発生します。
onConfigure メソッド
onConfigure()
メソッドはページ部品の可視性(可視・不可視)や有効性(活性・非活性)を制御する最適の場所として導入されました。このメソッドは描写が始まる前に呼び出されます。6.1.章で言及したようにisVisible
とisEnabled
はページ部品の描写中に何度となく呼び出されるため、これらのメソッドを直接オーバーライドすることは強く__推奨されず__、それよりもonConfigure
を用いて状態を変更するべきです。(次の節で説明する)onBeforeRener メソッドはこれとはまったく逆に、ページ部品を不可視にした場合にはそもそも呼び出されないため、この手の処理を意図したものではありません。
onBeforeRender メソッド
この段階でも最も重要なフックメソッドはおそらく`onBeforeRender()です。このメソッドはページ部品が描写処理に入る前に呼び出され、その子となるページ部品の構造を変更する最後の機会になります。
もしも子となるページ部品を追加したり除去したりしたいのであれば、ここが最適の場所です。次の例(LifeCycleStagesプロジェクト)では描写されるたびに異なる2つのラベルを交互に表示するページを作っています:
public class HomePage extends WebPage
{
private Label firstLabel;
private Label secondLabel;
public HomePage(){
firstLabel = new Label("label", "First label");
secondLabel = new Label("label", "Second label");
add(firstLabel);
add(new Link("reload"){
@Override
public void onClick() {
}
});
}
@Override
protected void onBeforeRender() {
if(contains(firstLabel, true))
replace(secondLabel);
else
replace(firstLabel);
super.onBeforeRender();
}
}
onBeforeRender()
内のコードはささいなもので、ページ部品の木構造にfirstLabel
とsecondLabel
のどちらが存在するかを調べ、存在するものをもう一方のものと交換しています。
このメソッドは子となるページ部品のonBeforeRender()
の呼び出しも行っているため、オーバーライドするときにはsuper.onBeforeRender()
を呼びださなくてはなりません。ただしonInitialize()
とは異なり、カスタマイズコードでの変更を子となるページ部品の描写に反映するため、親クラスのメソッドの呼び出しは一番最後でなくてはなりません。
上の例ではF5キーを押すか、リロードボタンを押すかして描写中段階を発生させなくてはならない点には注意してください。
もしも親クラスのonInitialize()
やonBeforeRender()
の呼び出しを忘れた場合、Wicketは以下のメッセージでIllegalStateExceptionを発行します。
java.lang.IllegalStateException: org.apache.wicket.Component has not been properly initialized. Something in the hierarchy of has not called super.onInitialize()/onBeforeRender() in the override of onInitialize()/ onBeforeRender() method
onComponentTag メソッド
onBeforeRender(ComponentTag)
メソッドはページ部品のタグ引数のorg.apache.wicket.markup.ComponentTag
を通して自由に処理してもらうために呼び出されます。例えばput(String key, String value)
メソッドやremove(String key)
メソッドでタグ属性の追加/除去ができ、あるいはタグの名前そのものを`setName(String)で変更することもできます。(次のコードはonComponentTagExampleプロジェクトのものです):
Markup code:
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<h1 wicket:id="helloMessage"></h1>
</body>
Java code:
public class HomePage extends WebPage {
public HomePage() {
add(new Label("helloMessage", "Hello World"){
@Override
protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
//Turn the h1 tag to a span
tag.setName("span");
//Add formatting style
tag.put("style", "font-weight:bold");
}
});
}
}
Generated markup:
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<span wicket:id="helloMessage" style="font-weight:bold">Hello World</span>
</body>
onInitialize
と同様にonComponentTag
をオーバーライドするとなったなら、親クラスでもタグのカスタマイズをしているかもしれないので、親クラスの同じメソッドを呼び出すのを忘れてはなりません。onConponentTag
のオーバーライドは特定のページ部品のタグをカスタマイズしなくてはならない場合には完璧ですが、同じコードを別のページ部品でも使いまわしたい場合にはこのフックメソッドの代わりにビヘイビアを使ったほうが良いでしょう。
タグ属性を操作する場合のAttributeModifier
ビヘイビアの使い方については既に6.2.章で見ています。19.1章ではそのベースクラスであるBehavior
クラスがフックメソッドの onComponentTag(ComponentTag)
の代替となるonComponentTag(ComponentTag, Component)
というメソッドを持っているのを見ることになります。
onComponentTagBody メソッド
onComponentTagBody(MarkupStream, ComponentTag)
メソッドはタグの中身を処理するために呼ばれます。入力としてonComponentTag
と同様にページ部品のタグを表すComponentTag
を受け取ります。それに加えてクライアントに返却されるページのマークアップストリームを表すMarkupStream
もあります。
onComponentTagBody
ではComponent
クラスのreplaceComponentTagBody
との組み合わせで特定状況にカスタマイズされたタグ内容を描写することができます。例えば(プロジェクトOnComponentTagExampleからのものです)ラベル部品が無効化されている場合にその内容の代わりに簡潔な説明文を表示することができます:
public class HomePage extends WebPage {
public HomePage() {
add(new Label("helloMessage", "Hello World"){
@Override
protected void onComponentTagBody(MarkupStream markupStream, ComponentTag tag) {
if(!isEnabled())
replaceComponentTagBody(markupStream, tag, "(the component is disabled)");
else
super.onComponentTagBody(markupStream, tag);
}
});
}
}
親クラスのonComponentTag
は標準のタグ内容描写処理を維持したい場合にだけ呼び出せば良い点に注意してください。(上の例ではページ部品(ラベル)が有効な場合のみになります)
7.5. 除去中(Removing stage)
この段階はページ部品がコンテナ(親あるいは他のページ部品)の木構造から取り除かれた時に発生します。この段階のフックメソッドはonRemove()
のみです。もしもページ部品が描写中に必要だった何かしらのリソースをまだ保持していたりする場合、このメソッドをオーバーライドしてそれを開放することができます。
一度ページ部品が除去された後は、それを同じコンテナに追加するのも別のものに追加するのも自由です。バージョン6.18.0以降ではさらに、一度除去されたページ部品が再度別のコンテナに追加されるたびに呼び出されるonReAdd()
というフックメソッドが追加されています。onInitialize
は__ページ部品がコンテナに初めて追加された時のみ__なのに対して、onReAddd
は__一度除去された後、追加される度__である点には注意してください。
7.6. まとめ
この章ではWicketページ部品のライフサイクル各段階とそれぞれに提供されているフックメソッドについて見てきました。これらのメソッドをオーバーライドすることでページ部品の構造を動的に変更したり、カスタムページ部品の振る舞いを強化したりすることができます。