なんかけっこう困っている人がいまだに多いようなので、昔mixiに書いてた自分用のまとめをこちらに転載します。
試した環境:
apr-1.3.2
tomcat-native-1.1.14
sun-jdk-1.6.0.07
tomcat-6.0.16
ipv6 enabled gentoo linux(2.6.26 base kernel)
tomcat6には実装が異なる3種類のHttp Connectorが付属しています。
参照: http://tomcat.apache.org/tomcat-6.0-doc/config/http.html
(機能や特性の比較表がこのページの一番下にある。)
org.apache.coyote.http11.Http11Protocol
Pure Javaコネクタ。ブロッキングIO。昔からあるやつ。
以降、Traditionalコネクタとする。
org.apache.coyote.http11.Http11NioProtocol
Pure Javaコネクタ。SSLのハンドシェイクに関してノンブロッキングIOをする。
NIOを利用したもの。tomcat6から利用可能。
以降、NIOコネクタとする。
org.apache.coyote.http11.Http11AprProtocol
Nativeコネクタ。tomcat-nativeを経由してaprを利用する。
以降、Nativeコネクタとする。
どのコネクタを利用するかは、server.xml(gentooだと/etc/tomcat-6/server.xml)
で設定します。(server.xml内のConnector要素、protocol属性の値)
javaでは、今のとこipv6な環境でipv4のアドレスを積極的に使用するには、
-Djava.net.preferIPv4Stack=true
を指定してjavaを起動しなければなりません。
gentooの場合、/etc/init.d/tomcat-6をそのまま使用するなら、
/etc/conf.d/tomcat-6に
JAVA_OPTS=”-Djava.net.preferIPv4Stack=true”
or
CATALINA_OPTS=”-Djava.net.preferIPv4Stack=true”
とします。
ですが、tomcat-native経由の場合は、このプロパティ値の影響を受けないようです。
そこで、いろいろ試してみました。
デフォルトの設定
<Connector port=”8080” protocol=”HTTP/1.1”
connectionTimeout=”20000”
redirectPort=”8443” />
protocol=”HTTP/1.1”の場合は、tomcat-nativeが利用できる環境では、
Nativeコネクタが使用され、利用できない環境ではTraditionalコネクタ
が利用されます。
tomcat-nativeあり -> IPv6でlisten(Nativeコネクタ)
tomcat-nativeなし -> IPv6でlisten(Traditionalコネクタ)
tomcat-nativeなし & preferIPv4Stack=true -> IPv4でlisten(Traditionalコネクタ)
つまり、インストール直後はtomcat-native環境では、
どうあがいてもIPv6でlistenされるということになります。
次に、address属性の値にIPv4アドレスを指定してみます。
<Connector port=”8080” protocol=”HTTP/1.1”
connectionTimeout=”20000”
redirectPort=”8443”
address=”0.0.0.0” />
tomcat-nativeあり -> IPv4でlisten(Nativeコネクタ)
tomcat-nativeなし -> IPv6でlisten(Traditionalコネクタ) <- これおかしくない?
tomcat-nativeなし & preferIPv4Stack=true -> IPv4でlisten(Traditionalコネクタ)
tomcat-nativeなしだと、address属性にIPv4アドレスを指定しても、
なぜかIPv6でbindされてしまう。この特性は、NIOコネクタを使用しても同じ。
NIOコネクタを使用する設定。
<Connector port=”8080”
protocol=”org.apache.coyote.http11.Http11NioProtocol”
connectionTimeout=”20000”
redirectPort=”8443”
address=”0.0.0.0” />
tomcat-nativeあり、なし関係なく、
preferIPv4Stack=true -> IPv4でlisten(NIOコネクタ)
preferIPv4Stack=false -> IPv6でlisten(NIOコネクタ) <- これおかしくない?
この結果、
Nativeコネクタは、
Connectorのaddress属性にIPv4アドレスを指定するだけで、IPv4アドレスでlisten。
Traditionalコネクタ、NIOコネクタは、address属性へのIPv4アドレス指定かつ、
preferIPv4Stack=trueでIPv4アドレスでlisten。
という結果になりました。
同様に、Apacheと接続するのに使用されるAJPコネクタも、
tomcat-native経由とそうでないものがあります。
tomcat-native環境だと、address属性の指定のみでIPv4アドレスでlistenし、
tomcat-native環境以外では、加えてpreferIPv4Stack=trueも必要です。
気になるのは、NIOコネクタとNativeコネクタの性能差ですね。
どちらのパフォーマンスがよいでしょうか。もしくは、使い分け方。
知っている方おしえてください。
フォームの部品個別にバリデーションとモデル取り出しを行う方法。
ModalWindowから戻るときに走らせる処理の登録方法。
チェックボックスとラベルを関連付けるときに、labelタグでinputタグを囲んでfor属性でinputタグのidを指定する方法がありますが、wicketがinputタグのidを勝手に振ってしまうので、この記事にあるように書けば大丈夫だよと。
パスワードの強度を文字入力の度にチェックするようにPasswordTextFieldを拡張しています。
wicketで作成するログインページは、ステートレスであるべきです。じゃないとログイン画面を表示しようとして、page expiredになってしまうことがあります。
ORMを利用してEntityを扱う際に、上手にwicketに組み込む方法。
後半部分の意味ですが、LoadableDetachableModelを継承する方法だと、まだデータベースに登録されていないentityの場合、当然serializationで復活してきません。これが困るシチュエーションは、フォームで新規登録も可能な画面の場合です。情報を入れかけたけど、保存せずに別のページに移動後、再びブラウザバックで戻ってきたら先ほど入れた情報は失われてしまっています。そこで、idがまだ振られていないentityだったら、entity自体をserializationの対象にするという戦略を取っています。detach()メソッドでその細工を行っています。
LoadableDetachableModelのdetach()は、普通のpublicメソッドでありオーバーライド可能ですが、privateなメンバに対する操作をしていて、その処理をつぶしてしまうと動作しなくなります。それで、IModelから継承する必要が出てきているわけです。また、load()がnullを返した場合も、LoadableDetachableModelは、エラーにせずにattach済み状態となります。load()からRuntimeExceptionをthrowすれば、エラー状態にすることが可能ですが、このページにある様に、nullだったら特定のExceptionをthrowすることを汎用的に実装したい場合にも、detach()と同じ理由でgetObject()が事実上オーバーライド不可なので、LoadableDetachableModelは使用できません。そういう意味では、LoadableDetachableModelのdetach()とgetObject()はfinalにすべきですね。
Wicket 1.4.2のコードで確認しています。
GuiceのServletModuleからWicketFilterを設定する方法。
public class ServletModule extends com.google.inject.servlet.ServletModule {
@Override
protected void configureServlets() {
serve("/myapp/foo").with(FooServlet.class);
serve("/myapp/bar").with(BarServlet.class);
Map params = new HashMap();
params.put("applicationClassName", "com.myapp.MyWicketApplication");
params.put("filterMappingUrlPattern", "/myapp/*");
filter("/myapp/*").through(WicketFilter.class, params);
bind(WicketFilter.class).in(Scopes.SINGLETON);
}
}