( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

Wicket1.5で導入されるNew Event SystemをScalaでエロガントに実装する

もう2週間以上前にもなりますが、Wicket勉強会 2011-01 : ATNDに行ってきたんですよ。


そこでWicket1.5からNew Event Systemってのが導入されてこれはScalaと相性いいんじゃね?みたいな 話になって、そりゃ俺に対して振ってるんだな、と思って書いてみましたが、そんなことより その後のさゆりさんがどうなったのか気になります。届け!この想い!!


Wicket勉強会開催直前です。 - 矢野勉のはてな日記
はてなブックマーク - Wicket勉強会開催直前です。 - 矢野勉のはてな日記

New Event Systemって

くわしくは以下の資料を見てくださいね。

http://public.iwork.com/document/ja/?a=p38265472&d=Wicket勉強会201101.key


簡単に言うと、コンポーネントとかがイベントを発行したり、イベントを受け取って処理ができたりなようはおなじみのアレです。
イベントとして、任意のオブジェクトをメッセージとして投げることができる。わお!


だが、 いかんせん実装がダサイ。イベントが発行されると、受け取り側のonEventメソッドが呼ばれるので実装しなきゃならないんですが、 こんなコード書かなきゃいけない。

@Override
public void onEvent(IEvent<?> event) {
    super.onEvent(event);
    if (event.getPayload() instanceof ImageRefresh) {
        if (selected) {
            source = null;
            selected = false;
            ImageRefresh<?> imageRefreshPayload = (ImageRefresh<?>) event.getPayload();
            imageRefreshPayload.addComponent(this);
        }
    }
}

引数にはIEvent<?>型で、そのIEvent#.getPayload()を呼ぶことで、イベント発行元が投げたメッセージオブジェクトを取得できます。
しかし、なんのオブジェクトが入ってるかわからんので、onEventの引数型はIEvent<?>で中身の型情報は失われており、従ってgetPayloadは Object型を返す、と。


そして、具体的なイベントの種別を判定するために"event.getPayload() instanceof ImageRefresh"とかやらなきゃいけない。
ダサすぎて牛乳吹くわ。"instanceof"が許されるのは(ry

Scalaでやってみる

この手の型に応じた処理の振り分けをScalaで行う場合、ふたつの選択肢があります。ひとつはパターンマッチングで型パターンを指定する方法、 もう一つはgeneralized type constraintsによる型パラメータによるメソッド定義です。


後者の方法は、様々な型のイベントを受け取れるようにするためには向いてないので、ストレートに前者の方法で実装しました。


では、デモで使用されたサンプルを改修してみます。元のソースコードはこちらです。

tyano/wicket15sample · GitHub


で、こちらがイベント処理周りをScalaで書き換えたものです。

yuroyoro/wicket15sample · GitHub

Eventを受け取ることができるtrait ReactableComponent

onEventを実装し、イベントを振り分けるtraitとしてReactableComponentを用意します。

trait ReactableComponent extends Component {
  // このtraitはComponentにmixinできる
  this: Component =>

  // イベントを処理するPartialFunction[Any, Unit]
  private val handlers = scala.collection.mutable.ArrayBuffer.empty[PartialFunction[Any, Unit]]

  // 引数のPartialFunction[Any,Unit]をイベントハンドラとして登録する
  final def handler( f:PartialFunction[Any,Unit]):Unit = {
    handlers += f
  }

  override final def onEvent(event:IEvent[_]):Unit = {
    val e = event.getPayload
    // 登録されてるPartialFunctionで処理できるものにイベント処理を行わせる
    handlers.filter{ _ isDefinedAt e}.foreach{ f => f(e) }
  }
}

このtraitは、self type annotationでComponentにmixiinされる前提です。


handler関数で引数にもらったPartialFunctionをイベントハンドラとして覚えておき、 onEventが呼び出されるとhandler関数で登録されたPartialFunctionのうち、イベントが処理できるものに処理を行わせるようになっています。


ScalaのPartialFunctionが便利ですよ - ゆろよろ日記

具体的なイベント処理を行うtrait EventReactor

次に、実際にそれぞれのイベント処理を行うtraitとして、EventReactorを用意しました。
メッセージに対応した処理を行う各handlerは、このtraitを継承します。

trait EventReactor extends Component {
    this: ReactableComponent =>
}


EventReactorは、self type annotationでさっきのReactableComponentがあらかじめmixinされてる前提です。
ReactableComponentで定義されているhandler関数をするためです。


では、実際のhandlerを見てみます。以下は、RemoveRequestというメッセージを受け取ったら自信を非表示にする処理を 行うRemoveReactorと、ImageRefreshイベントを受け取ったら画像のsrcのURLをリフレッシュするImageRefreshReactorです。

trait RemoveReactor extends EventReactor {
  this:Component with WebMarkupContainer with ReactableComponent =>

  handler{
    case event:RemoveRequest => setVisibilityAllowed( !event.isRemove )
  }
}

trait ImageRefreshReactor extends EventReactor {
  this: Component with ReactableComponent with ImageSrcComponent with SelectableComponent =>

  handler{
    case event:ImageRefresh[_] =>
      if (selected) {
        reload()
        selected = false
        event.addComponent(this)
      }
  }
}


具体的なイベント処理は、handler関数にPartialFunctionで渡している箇所で行っています。handler関数は PartialFunctionを引数にとり、かつ{case x:Type => ...}のように書くとPartialFunctionに変換される、という仕組みを利用しています。


実際に、これらのtraitをmixinしたコンポーネントを見てましょう。

class RssImage(id:String) extends AjaxLink[java.lang.Void](id)
  with ReactableComponent
  with ImageSrcComponent
  with SelectableComponent
  with ImageRefreshReactor
  with RemoveReactor {

  import scala.util.control.Exception._

  def getImageSource() =  allCatch opt{
    val app = WicketApplication.get
    val rss = app.getRssSource
    val entry = rss.getRandomEntry
    entry.getEnclosures.get(0).asInstanceOf[SyndEnclosure].getUrl
  }

  override def onClick(target:AjaxRequestTarget ) = {
    selected = !selected;
    target.add(this);
  }
}


AjaxLinkを継承したRssImageは、ImageRefeshReactorとRemoveReactorをmixinしているため、RemoveRequestを受け取ると非表示になり、ImageRefreshを受け取ると画像を再描画します。しかし、このComponent自身にはどこにもイベント処理が記述されていません。


EventReactorトレイトがイベントの型を型パラメータまたは抽象型メンバーでもらわない設計になっているのは、ちゃんと理由があります。

trait EventReactor[A] {...}
trait RemoveReactor extends[RemoveRequest] {...}
trait ImageRefeshReactor extends[ImageRefresh] {...}


上記のような設計になっていないのは、RemoveReactorとImageRefreshReactorが同じComponentに同時にmixinされる可能性があるためです。同じ継承先のEventReactorの型変数をそれぞれ違う型でextendsしたtraitを同時にmixinすると、traitの線形化ができなくなってコンパイルエラーとなります。

traitによって個々の処理をPartialFunctionで登録するパターンマッチング

traitで処理を定義してる、handlers{ case x:Type => ...}って箇所、何かに似ていると思いませんか?
これは、scalaのActorライブラリでのメッセージ処理に似ています。ってか、このアイデアはActorからぱくりました。


加えて、self type annotationでmixinできる対象を限定し、self type annotationで指定した型に定義されている関数などを使ってtrait側で抽象化した処理を実装できるようになっているのがポイントです。


WicketのComponentのように複雑なクラス階層に対して横断的にtraitで処理を織り込む方法は、AOPに似てますがはるかに簡潔で安全です。


ね?Scalaって、エロガントでしょう?

Wicket勉強会 第2回に参加してLTでWickextの話をしたってね?

Wicket勉強会 第2回に参加してきましたよ。
第1回が50人、第2回が80人の参加です。wicket大人気じゃね?
このペースだと次は100人超えるのでは・・・。


会場は、前回のjava-jaでもお世話になったGREEさん
GREEパネェ


主催のid:t_yanoと参加された皆さん、お疲れ様でした。

LTでWickextの話をしたよ

ってことで、WickextというWicketの拡張ライブラリについてちょっと話してきたんだよ。
WickextってのはWicketJQueryを組み合わせていい感じにするヤツなんだぜ?


最初はLTの抽選漏れかと思ってorzだったので、先走って資料をSlideShapeにうpして供養した。
と思ったらやっぱりLTあった。資料が無駄にならなくてよかったよ!



公式サイト:
http://www.wickext.org/


Google Code:
http://code.google.com/p/wickext/


使ったデモとソース:
http://wickext-sample.yuroyoro.staxapps.net/
http://github.com/yuroyoro/wickext-sample/tree/master


資料の中にネタを仕込めなかったのが、今回の反省点ですw

懇親会

自重せず朝6時まで飲んでマスタ。
ダメな大人ですね。


id:cuctusmanが、gitもmercurialPOSIX準拠のシステムコールを使ってるので移植性が悪いからjavaで分散バージョン管理システム作るべき!と言っていたのが印象に残ってる。
あと、はてなキーワードのバグとか。


帰ったら、やっぱり嫁に怒られましたorz。

発表内容メモ

id:yoshiori AjaxComponentの作り方

Tapestory5がすげーいいってmjd?

  1. markupはxmlって
  2. アノテーションでステートフルを指定


GxPぱねぇw


やること

  • jsをheaderに読み込ませる
    • HeaderContributerでやる
      • rederHaed()で書き出し。JavascriptResourceReferenceで書く。
  • AbstractAjaxBehavior
    • getCallbackUrl()でコールバックのURLが分かる
wicketの開発事例
  • 財務分析するツールをWicketで作った。
  • YUIのテーブルぱねぇ
  • デザイナー指向とコンポーネント指向
  • どっちもメリット/デメリットあるよ。

スクロールとかぐりぐりする表スゲー。
公開マダー


プログレスバーとかメモリ使用量表示とかMbeanとか、マニアックなw


YUIスゲー。こんど触ってみよう。


デザイナーにWicket勉強させるとかパネェ

id:akr htmlをプレビューする方法
  • ResrouceStreamLocatorで階層を浅くする
  • WEB-INF以下のhtmlを置く。

オフラインでのプレビュー

  • パスは相対パスである必要がある。
  • webapp直下にhtmlおいてみる

ほかには

  • wicket:linkでパッケージリソースとして解釈させる。
  • wicket:remove + HeaderContributor
公開する前にやっておくこと

実運用の話。

  • エラーページを変更する。
    • 自分でExpredPageを作る
    • WebPageクラスを継承したPageを作る
  • robot.txt
    • HybridUrlCodingStrategyが良い思う
  • :jsessionid
    • getClientInfo
自社フレームワークWicketを採用した話
id:nagaseyasuhito 携帯向けWicket Tips
  • 日本語表示されない
    • setEscapeMarkuplStringsをよぶ
    • ComponentInstanciationListnerでやった
  • value="0"
    • KDDIの端末ではチェックボックスoffでvalue="0"
    • SimpleAttributeModifierというBehaviorを追加して対応
  • RFC違反なメルアド
    • Wicket標準のバリデータはdocomoとかはダメ。
  • 電話番号をLinkにする
    • SmartLinkLabel。httpやmailtoは自動的にLinkになる。DefaultLinkParserを継承して090-とかをLinkにした。
  • getパラメータを付与する
    • docomoのGUID=ONとかは、onComponentTagを実装してやる。Tagのbodyとかがとれるのでここでいじる。

いがいとPCと変わらなくいける。
PageClassは一つでPCと携帯でhtmlを切り替える。

id:bose999 Wicket+EJB3 on JBoss

Wicket勉強会に行ってきましたよ。

行ってきました。30人くらい来てた。
参加した皆様お疲れ様でした。

感想

  • 参加者はみんなアツい。Wicket大人気じゃね?
  • LTがちょっと間延びしたかな。発表するほうも時間を気にしてて集中できてなかったみたいだし。
  • 金曜夜って日程はよかった。
  • 次回はハンズオンでコーディングとかあったらいいな。
  • Wicketのソース読みましょうとかもいいかも
  • むしろ最初から懇親会とかでも。
  • 次回は何か発表できるように頑張る

ほかの人の感想など。
GlassFish Server Open Source Edition 3.1.2 - Error report
第一回wicket-ja勉強会に参加&LTしました - 凡人プログラマ
第一回wicket勉強会 | tsuyuki.makoto
Scala-ja - 資料館

以下メモ。

矢野さん

ステートフル
  • あぶくのようなオブジェクト。ポニョwww
  • 通常のWebアプリだとリクエストごとにオブジェクトの状態管理が発生する。
  • swingはそんなことねぇよ。
  • Webアプリとデスクトップのつくりはだいぶ違う
    • MVCの意味がまったくちがう

Wicketの目指すところ

デスクトップアプリのようにリクエストを超えてオブジェクトが存在するように!

  • Webの場合はセッション
  • Wicketでは、セッションはJVMのHeapと同じようなもの。
    • Wicketが状態を維持する!
    • ex)オブジェクトのバージョン管理。
  • バックボタンをUNDOにする。
    • (command patternが実装できる!)


メモリ大丈夫?

  • Wicket1.3から導入。ワークディレクトリの中にファイルが作られてキャッシュされる。(セカンドレベルキャッシュ)
  • セカンドレベルキャッシュはいつ消える?
    • Wicketの設定があって、ページオブジェクトのバージョンをいくつもつか設定できるデフォルトではバージョン5まで。
    • セッションが消えるとキャッシュも(wicket上から)消える。
    • 実ファイルが消えてるかどうか不明。
    • ModelとかはSerializableでないと、developmodeでエラーとなる。


クラスタリングは?

  • アプリケーションサーバのセッション同期に任せていた。
  • 同期するときにセカンドレベルキャッシュもなんか同期してるみたい。
  • コミッタ的には、「Wicketでやるとこじゃねぇよ。」

Ajax

DOMエレメント=コンポーネント

  • wicket:idを付ける部分はDOMツリーと一致している。
  • コンポーネントを更新する = DOMエレメントを更新する。


ビベイビア(振舞)

  • あらゆるコンポーネントにあとから[振舞]だけを追加できる。
  • 10秒単位で更新など。
  • inplaceeditorなど。
  • ほとんどのビヘイビアはajax


課題

  • コンポーネントの差し替えが基本で、エレメントの追加が苦手。
  • あらかじめテンプレートに仕込んでおく必要があるので面倒。
  • 10個から11個に追加する場合は、11個丸ごとサーバから送る。


DOMのIDと相性が悪い。

  • wicketからIDを操作するときにDOMにすでにIDがついていたらそれを使う。
  • うまく動かない。
  • こみったは後回しにした。

ライブコーディング

1.4-m3で。例のみんな大好きなサービスを150行で作るぞ

  • 実際は160行くらい。160行のほとんどが日付計算www

ログイン画面

  • 例のアレのHTMLをぱくってwicket:idを埋める。
  • Login.html
  • Login.java-Page.classのサブクラス
    • RequiredTExtFieldとPasswordFieldをadd
    • AbstractValidatorの無名クラスをadd
    • AbstractValidatorはデフォルトでブランクチェックしている
  • moutBookmarakablePageでURLをきれいに。


メッセージ表示する画面

  • timelineの取得はtwitter4Jでやってる。
  • tiwtter4jのstateオブジェクトをmodelとしてComponetnと結びつける。
  • Modelの状態が変わると自動的にcomponentの表示が変わる。
  • TimelineTable(Listview)にAjaxSelfUpdatingTimerFileterBehaviorってビヘイビアをaddすると一定時間ごとに表示を更新する。
    • ビヘイビア様最高
  • デバッグモード起動すると、ページ上にデバッガが出てくる。
    • XHRの内容とか、AJaxで通信しているログとかが出る。
    • Firebugがあるからあまり使ってなかったけど。IEとかでは便利。

質疑応答

  • JQueryとかとの組み合わせはキモイ?
    • wicketのexsampleやwicket stuffとかで実際にやっている。
  • Ajaxでのページバージョンの変更はどのタイミング?
    • sumitするとwicketが認識。
    • Modelに対して今から触る通知するメソッドがあるのでそれを使う。
    • XHRとかを直でやった場合の話で、AjaxSubmitBottonだと大丈夫。
  • AWTっぽくね?
    • 内部的にはListnerだらけ。
  • 自分でListner作れない?
    • 公開されている奴もある。
    • 実はonhogehogeとかがあるのでそれで何とかできることも多い。(commiterいわく)
    • id:t_yano的にはlistnerはただ処理をスルーするだけ。
  • Componetを作るときには継承モデルの方がわかりやすい?
  • wicketAPIは基本的に非公開。言ったら次期リリースで公開されるとか。


たけうちさん

wicketの特徴

  • 拡張性が高い。
  • 高LV、低LVでいろいろ出来る


Component Resolver


IComponentResolver

  • HTMLにWicket:idがあって、Componentがaddされていないと呼び出される。
  • PageやPanelにImplementする
  • 解決できなかったコンテナ、変換中のストリーム、解決できなかったComponentTagのオブジェクト
      public boolean resolve(MarkupCOntainer container, mMarkupuStereamd markupSterem,ConponentTag tag){
         if( tag.isAutoComponentTag() ){
           return false;
           
         Label label = new Label( tag.getId(),);
         return container.autoAdd(label,markupStream);
      }
  • タグの属性(attribute)を取得できる。

CompoundPropertyModelと組み合わせるとTeeda的なものができる。

S2Wicketのときはアノテーション的なものがあったけど、Wicketでやる必要がある?
ってかせっかくjavaでやれんのにテンプレートにゴリゴリ制御書くってどうなん?

  • 宗教論争
  • 本人が楽しければいんじゃね?投げっぱなしwww

DIの問題。

  • DIコンテナとバッティング。
  • wicket-ioc
    • クラスのフィールドをproxyとして利用する
    • wicket-spring,wicket-guiceとかが使ってる
    • ReloadableWicketFilterでなんとか・・・
    • もうClassLoader自作するしかないんじゃ…。

LT

LTじゃなくてプレゼンだよね。全然5分でおさまってない。

Kishiさん

Wcketを使って[こうなる]を作った。
予測市場(仮想の株式市場)を使って将来を予測する手法。
prototypeとscript.acur.usを使ってる。

Tips

  • のはなし
  • URLをCoolに
    • mountbookmark
    • HybridUrlCodingStrategyを実装する
    • IndexedParamUrlCOdingStrategy,MixedParamUrlCoding
  • RestartResponseExceptionを使うとURLが変わらない。
    • IEで動かない。
    • ModelがSerializableじゃなかった
ぎしさん

運用の事例。グループウェア
教育コストと生産性の話

けいすけん

Scala on wicket

  • liftはまだ実績がない。
  • @BeanPropertyでclass定義とconstoructorが簡単に。
  • クロージャとカリー化
    • Implicit Conversions
    • Componentやvalidatorの処理を型推論で簡単に
    • これは便利そう


っていうかscalaの紹介だった。個人的には面白かったけど。

田中さん

不動産広告系ASPサービスのWebアプリの事例

  • 前任者の暴走で採用www
  • wicket1.2系
  • APサーバ WLS9 JBOSS4
  • ibatics

  • wicket-auth-roles
  • PVは月間60万位 運用2年。
  • WLSのセッションDB保存機能を利用。
  • 項目が多いのでCSVで画面定義を書いてcomponentを生成して処理。
    • pageクラスのほうはなんとか頑張る
  • CMSもつくってる
    • StringRequestTargetでViewにVerocityを採用

よかった探し

  • デザイナとの協業がうまくいった。
  • デザイナがhtmlいじってSVNにコミット。
  • 完全に分業できた。


困ったところ。

  • 知ってる人はまだ少ない。
  • 日本語リソースはまだ少ない。

Wicket1.4-m3ではComponentはジェネリクス化されないってよ。

Wicket 1.4でのGenerics化にて大論争 - 矢野勉のはてな日記
この件に関して、1.4-m3である程度の方針が固まった模様。


すでに皆さんが書いてますが、いまさらながら。
2008-07-16 - マイペースなプログラミング日記
Wicket 1.4-m3 で Generics の仕様変更 - まどぎわBLOG


Wicket公式より。一部のComponentを除いて型パラメータは取らないようだ。

A significant change from the earlier Wicket 1.4 milestone versions is that Component is no longer generified. This means that Component and most of its subclasses in Wicket do not take a class-level type parameter. Some Component subclasses remain generified, such as

* Link
* FormComponent
* Form
* many repeater components such as RefreshingView, DataView, ListView
o Item, ListItem

以前のget/setModelメソッドは、get/setDefaultModelというように、Defaultをつけたメソッドにメソッド名が変更されており、ジェネリクス化されたComponentでpublic final T getModelObject()を実装すべし、とある。


getModelの型パラメータ記述がめんどくせぇってことで、今まで通りModelの型を指定しない場合はget/setDefaultModelを使って、型を気にする場合はComponent側に T getModelObject()とかが実装されているはずなのでそれを使えってことらしい。

この方針に関しては、良いと思う。メソッド名さえ変えれば、今まで通りに書けるしね。


であれば、型パラメータ化されたget/setModelObjectはinterfaceとして切り出されているのかと思ったら、どうも何もないようだ。

Componentがジェネリクス化されているかどうかは、T get/setModel()が実装されているかどうかで判断せよってこと?

個人的には、ジェネリクス化されているかは型で判断したいけど。

こんな感じのinterfaceを用意しておいてジェネリクス化されたComponentはこのinterfaceを実装する、とかじゃダメなのかな?

public interface GenerifiedCompoent<E> {
	
	public  E getModelObject();
	public  void setModelObject(E model);

}

このinterfaceを実装するComponentは、自身の型パラメータとInterfaceの型パラメータを同じにする。
GenerifiedCompoentをimplementsするときの型パラメータを、Class定義の型パラメータで受けるってこと。

public class MyComponent<T> extends Component implements GenerifiedCompoent<T>{

	public T getModelObject() {
		return (T)getDefaultModelObject();
	}

	public void setModelObject(T model) {
		setDefaultModelObject(object);
	}

	@SuppressWarnings("unchecked")
	public final IModel<T> getModel()
	{
		return (IModel<T>)getDefaultModel();
	}

	public final void setModel(IModel<T> model)
	{
		setDefaultModel(model);
	}
}

単に、get/setModelが個々のComponentに分散されているのが個人的に気持ち悪く、ジェネリクス化されたComponentに共通の何かがあればいいなと思っただけで。

IDE使う場合は、コンポーネントをnewするときに型パラメータの指定を求められるし、ComponentからModelを取得したい場合は、とりあえずgetModelって打ってみてメソッドが実装されていればそれを使うだろうし。

まぁ、あまりinterfaceにするメリットはないかなぁ。

AjaxButtonとかをShift_JISのページで利用すると文字化けする件について

Wicket-jaのメーリングリストで報告した件ですが、こちらにも載せておきます。
http://lists.sourceforge.jp/mailman/archives/wicket-ja-user/2008-April/000072.html

Wicketにて、
getRequestCycleSettings().setResponseRequestEncoding("Shift_JIS");
でページのエンコーディングUTF-8以外にして、AjaxButtonをaddしてSubmitさせると、送信されるフォームの内容が
文字化けします。


原因は、AjaxButtonがsubmit時に実行するJavaScriptの中で、
encodeURIComponent()にてPOSTデータはページエンコーディング
かかわらずutf-8になってしまうためです。
ブラウザからはutf-8でリクエストが送信され、Wicket側はetResponseRequestEncoding()で設定された文字コードでフォームデータをデコードするため、ここで文字化けが発生します。


id:t_yanoが本家にバグ報告をしてくれています。
https://issues.apache.org/jira/browse/WICKET-1569
なので、そのうち直ると思いますが、現時点では、以下のようなFilterをWicketFilterの前にかましてやれば対処は可能です。
(packageは適当になおしてください)

package com.yuroyoro.wicket;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;


public class AjaxEncodingFilter implements Filter {

	/* (非 Javadoc)
	 * @see javax.servlet.Filter#destroy()
	 */
	public void destroy() {

	}

	/* (非 Javadoc)
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		HttpServletRequest httpServletRequest = (HttpServletRequest)request;
		String ajaxHeader = httpServletRequest.getHeader("Wicket-Ajax");

		if (ajaxHeader != null && ajaxHeader.length() > 0 && ajaxHeader.equalsIgnoreCase("true"))
		{
			httpServletRequest.setCharacterEncoding("utf-8");
			request = new HttpServletRequestWrapper(httpServletRequest){

				/* (非 Javadoc)
				 * @see javax.servlet.ServletRequestWrapper#setCharacterEncoding(java.lang.String)
				 */
				@Override
				public void setCharacterEncoding(String enc)
						throws UnsupportedEncodingException {
					// 何もしない
				}
				
			};
		}

		chain.doFilter(request, response);
	}

	/* (非 Javadoc)
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	public void init(FilterConfig filterConfig) throws ServletException {

	}

}

S2WicketをWicket1.3に対応してみた

といっても、パッケージ名とTestクラスを直しただけ。
あと、Wicket1.3からはFilterになってるので、S2Containerの生成にS2ContainerServeltが使えなくなった。
ので、S2ContainerListenerで生成してやればおっけ。
web.xmlにこんな感じで追加しましょ。

	<listener>
		<listener-class>org.seasar.framework.container.servlet.S2ContainerListener</listener-class>
	</listener>

って、もうすでにやってる人がいたのね。
http://d.hatena.ne.jp/NAGASEYASUHiTO/20070707/1183782802

AjaxButtonでエラーが発生したときに、FeedbackPanelを更新する方法

FeedbackPanelをaddしておくと、validateでエラーになったメッセージを勝手に表示してくれて便利。
で、ふつーのButtonだったら問題なしだけど、AjaxButtonでsubmitしてる場合はちょっと注意。

っていうのは、AjaxButtonのonError()で、FeedbackPanelを更新するように、AjaxRequestTargetにaddする必要がありまっせ。
当然、FeedbackPanelはsetOutputMarkupId( true )としておく必要あり。

    FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
    this.feedbackPanel.setOutputMarkupId( true );
    add( feedbackPanel );

    Form form = new Form( "requestForm");
    add( form );

    Button submitBtn = new IndicatingAjaxButton("submitBtn", form){
        @Override
        protected void onError(AjaxRequestTarget target, Form form) {
            target.addComponent( feedbackPanel );
        }
        @Override
        protected void onSubmit(AjaxRequestTarget target, Form form) {
            // submit処理
        }
    });