Servlet コンテナによって HttpServletRequest#getPart(String name) の挙動が違う
Part gotPart = httpServletRequest.getPart("hoge");
みたいなコードがあった時,送られてきた multipart リクエスト (httpServletRequest
) に1つも part が含まれていない場合の挙動が Servlet コンテナによって変わってきます.
送るリクエストはこんな感じ.
HttpPost post = new HttpPost("http://localhost:8080/"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); HttpEntity entity = builder.build(); // part は空のまま instantiate post.setEntity(entity); HttpClient client = HttpClientBuilder.create().build(); HttpResponse response = client.execute(post);
この場合に Tomcat 8.0.20 でこのコードを実行すると,gotPart
には null
が入ってきますが,
Jetty 9.2.9.v20150224 で実行すると,getPart("hoge")
の実行によって IOException
が上げられます.
Jetty の実装を見るとリクエストに form-data の行が無かった場合に IOException を上げるようになっているようです.
https://github.com/eclipse/jetty.project/blob/a3201a3c810da37ad892e62c1f04600dc889d14a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java#L490-L491
Jetty が IOException を上げてくるのが良いかどうかはさておき,ここらへん細かい差異があるので実装にあたって注意が必要ですねという印象です.
textsearch_sennaをキレイにアンインストールする
textsearch_sennaというのがあって,これはsennaを使った全文検索をpostgresqlに提供するために便利な演算子や関数を提供してくれるやつなんですが,これをアンインストールする必要が出てきた時に「インストール時に追加された関数とか演算子とかビューとか全部調べて手で削除しないとマズいのかーうへー」とか思ってたんですけど,そんなことする必要無かったのでメモ.
結論からいうと,$PG_HOME/share/contrib/uninstall_textsearch_senna.sql
を流し込んでやるとよろしい.このファイルはtextsearch_sennaインストール時に同時に提供されるファイルです.
psql --user=user_name -f $PG_HOME/share/contrib/uninstall_textsearch_senna.sql db_name
これで関連のものがDBから削除されるので,あとはtextsearch_sennaをインストールする時に使ったMakefileを利用して
PATH=$PG_HOME/bin/:$PATH make uninstall
などとしてやると完全にアンインストールされます.ちゃんとアンインストールの為のユーティリティが用意されていた!
ちなみになぜキレイに消し去らなければならないのかというと,pg_updateでpgサーバのバージョンを上げるとなった時に,新しいバージョンではtextsearch_sennaは必要無いのにも関わらず「古いバージョンがtextsearch_senna要求してるけど新しいバージョンにはtextsearch_sennaが入ってないよ〜」とか怒られて死ぬのでそれを回避する為です.
世の中には色々な理由があります.理由があるのです.
Servlet 3.0 から導入された multipart 関連の処理を Tomcat で有効にする術について
servlet 3.0 の multipart 関連処理を有効にする方法 - blog.64p.org
これの関連なんですが.
こういう設定をしておかないと,HttpServletRequest#getPart() や HttpServletRequest#getParts() が null を返してきてマジ意味わからん!!!! みたいな感じのキレるが発生いたします.
ところで,Tomcat で multipart 関連の処理を有効にする方法としては
1. web.xml
に設定を書く
2. Servlet クラスに対して @MultipartConfig
アノテーションで設定する
3. context.xml
か Tomcat/conf/server.xml
に設定を書く
の3つがあるようです.
1の方法は上のtokuhiromさんのエントリにあるように書いてやれば良いです.
<servlet> <multipart-config> <location>/tmp</location> <!-- ディレクトリパスを指定することも出来る (しなくても良い) --> <max-file-size>5242880</max-file-size> <max-request-size>27262976</max-request-size> <file-size-threshold>32768</file-size-threshold> </multipart-config> </servlet>
2の方法は Servlet クラスに @MultipartConfig
アノテーションで設定を書いてやるというものです.
@MultipartConfig( location="/tmp", // ディレクトリパスを指定することも出来る (しなくても良い) fileSizeThreshold=32768, maxFileSize=5242880, maxRequestSize=27262976 )
フームという感じです.
3の方法は webapp/META-INF/config.xml
や Tomcat/conf/server.xml
に以下の様な設定を書くという感じのやつです.
<Context ... allowCasualMultipartParsing="true" />
どれが best-way なのか,という話題ですが,まあアノテーションを使う方法2はちょっと無いですねという感じです.だるいですし,そもそもミドルウェアの関心事がアプリケーションのコードに記述されるというのは厳しい心境になります.
残る方法は1と3ですが,これはまあどちらでも良いのではという感じはあります.
web.xml
はアプリケーションの定義を書く xml ですが,まあ multipart の設定を書く程度なら妥当な感じはします (ただ,ディレクトリパスをハードコードで指定したりすると厳しいのではという意識があります).
config.xml
やserver.xml
に書くのは適切な感じがします.が,web.xml
や @MultipartConfig
アノテーションで出来るような細かな設定が出来ないのでびみょい場合はあると思います.
ここらへんは適宜使い分けていくという感じでしょうか.
参考
GitHub Releases にホストされている成果物の最新の奴を持ってくるワンライナー
GitHub Releases でホストされている任意のリポジトリの成果物の最新のやつを持ってきたくなるという事が人生では常に起こります.そしてそういう時は GitHub API の Releases のやつを使うと良いことがわかっています.
curl https://api.github.com/repos/moznion/java-mysql-diff/releases/latest | jq '.assets[0].browser_download_url' | xargs curl -L -O
簡単ですね! jq 便利!!
:= 演算子をなんと呼ぶのか問題
:= をなんと発音していいか分からないのでずっとち◯こ演算子って読んでる。
— Tomohiro Nishimura (@tomohi_ro) 2015, 2月 25
:=,個人的に「定義氏」って読んでる
— 初回 (@moznion) 2015, 2月 25
定義氏ではない,定義子
— 初回 (@moznion) 2015, 2月 25
定義子,Pascalかなんかの教科書に載ってた用語だった気がする
— 初回 (@moznion) 2015, 2月 25
「定義ちゃん」とか呼びやすい上に可愛らしくて良いかもしれない
— 初回 (@moznion) 2015, 2月 25
普通にコロンイコールって呼んでた
— 辛子明太子 (@pastak) 2015, 2月 25
本当はなんて読むのが正しいんですか.
[追記]
今Pascalの本を確認したら「定義子」ではなくて「代入演算子」と書いてあった……これをいつしか勝手に「代入子」と略しはじめて,それがどんどん変形していって「定義子」という造語を俺は勝手に作り上げていたのではないか……
— 初回 (@moznion) 2015, 2月 25
体調悪化してきた
— 初回 (@moznion) 2015, 2月 25
CentOS 6.6 上で NVIDIA の GPU (の一部) と共に nouveau 使うと発狂して死ぬ
タイトルの通りです.
CentOS 6.6 の上で NVIDIA の GPU の一部のモデルを nouveau と一緒に使うとカーネルパニックを起こして死にます.OS が起動しねえ.
一部というのは確認できた限り
- GTX 690
- GTX 590
- GTX Titan
- Tesla K20Xm
です.Quadro 系はなぜか大丈夫でした.環境に依る気がする.GeForce 系は軒並み死ぬのではないかと思います.
他の CentOS のディストリビューションについては調べてませんがまあ死ぬと思います.
ついでに言うと Ubuntu でも死にます.勘弁してくれ.
解決
nouveau がいくら自由な存在とてカーネルパニック起こしてクラッシュするのはどうしようもないので
NVIDIA のプロプライエタリドライバをインストールすることにします.
とにかく OS が起動しないとどうにもならんので OS を起動させます.
オンボードのグラフィック機構で起動させるか,クラッシュしない GPU を挿して起動します.
起動したらおもむろに RunLevel を 3 に変更します (もともと 3 ならしなくても良い).
$ sudoedit /etc/inittab id:3:initdefault:
ついでに nouveau を無効にします.これをやっておかないと NVIDIA のプロプライエタリドライバがインストール出来なくてキレる羽目になるので.
$ sudoedit /boot/grub/grub.conf (略) KEYTABLE=us rd_NO_DM rhgb quiet nouveau.modeset=0 # ~~~~~~~~~~~~~~~~~ 対象の kernel のオプションにこれを書く
ここで併せて NVIDIA のドライバのインストーラをダウンロードして然るべき場所に置いておきましょう.
そしてリブート.
リブートしたらドライバのインストーラを起動して,あとは適当にインストールしてゆきます.
インストールが終わったら RunLevel を 5 に戻す (もともと 3 ならそのままで良い).
$ sudoedit /etc/inittab id:5:initdefault:
そしてリブートすると直っているという感じです.タイミングで適宜所望の GPU に挿し換えておきましょう.
最初原因わからなくて困った.
Java で新しくプロジェクトを始めるときに何を使ってセットアップすべきか
Java で新しいプロジェクトを立ち上げる時,
という2つの方法が考えられると思います (他にもあるかも知れない).
さてどちらが良いのか.
Maven Archetype を使う
セットアップスクリプトを使う
利点
- 自由度が高い
- 例えば上に書いたコマンドライン引数に応じてファイルの出しわけをする (
--admin
オプションを付けると,管理画面用の雛形が追加されるみたいな) とかが簡単に実現できる
- 例えば上に書いたコマンドライン引数に応じてファイルの出しわけをする (
- ルールに縛られず自分の好きなように作れるので作りやすい
所感
とりあえず通常の場合は Maven Archetype を使っていくのが良いような気がします.
「Java のプロジェクトをやろう!」という人のマシンには間違いなく mvn は入っているでしょうし,なにより archetype は配布や実行が楽だからです.Maven Archetype は凝ったことをしない限り戦っていくことが可能です.
配布や実行が楽というのは本当に重要であります.この辺が面倒くさいと誰も使わないし,保守するモチベーションも死んでゆくし,その結果いくら良い雛形であっても滅亡してゆきます.ので,ここは本当に重要.
処理が重いというのはありますが,絶望的に重いわけではないのでここらへんは割り切っていきましょう.そんな頻繁に叩くものでもないので.
「Maven Archetype では無理だ!」というレベルの凝ったことをしたくなった時には独自のセットアップスクリプトを用意するくらいで良いという意識になっています.
この場合,セットアップスクリプトをどこに置くかという問題はありますが,そのあたりは GitHub Releases とか,Jenkins の成果物とか,まあいくらでもやりようはあるのかなと思っています.
(雑考: ここらへんに golang を使っていくというアプローチはどうか.ビルド済みのバイナリを然るべき場にソイヤしておくと,各位が適宜エイヤできる気がする)
archetype の作成はだるい,というのはまああるにはあるんですが,セットアップスクリプトを作る場合も結局は面倒なので,この辺は支配的な差にはならないように感じています.
Maven Archetype,最初はその風貌や名前からウッアッという感じになるんですが,慣れると何とかなります.
ひとまずこれで良いんじゃないですかね.