その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

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.xmlTomcat/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.xmlTomcat/conf/server.xml に以下の様な設定を書くという感じのやつです.

<Context
    ...
    allowCasualMultipartParsing="true" />


どれが best-way なのか,という話題ですが,まあアノテーションを使う方法2はちょっと無いですねという感じです.だるいですし,そもそもミドルウェアの関心事がアプリケーションのコードに記述されるというのは厳しい心境になります.

残る方法は1と3ですが,これはまあどちらでも良いのではという感じはあります.
web.xml はアプリケーションの定義を書く xml ですが,まあ multipart の設定を書く程度なら妥当な感じはします (ただ,ディレクトリパスをハードコードで指定したりすると厳しいのではという意識があります).
config.xmlserver.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 便利!!

:= 演算子をなんと呼ぶのか問題








本当はなんて読むのが正しいんですか.

[追記]


CentOS 6.6 上で NVIDIA の GPU (の一部) と共に nouveau 使うと発狂して死ぬ

タイトルの通りです.
CentOS 6.6 の上で NVIDIAGPU の一部のモデルを 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 を使う

利点
  • mvn さえマシンに入っていれば OK (他の処理系がいらない)
  • Maven Central (社内に立ってるようなミラーを含む) に archetype が上がっていると明示的なインストール等が無く使えるので便利
    • 配布が楽!!!!!!
    • 簡単に使える
      • アップロードされている場合,以下のようにするとセットアップできる
mvn archetype:generate -DarchetypeGroupId=com.example -DarchetypeArtifactId=sample-archetype -DarchetypeVersion=1.0.0
欠点
  • Archetype 作るのは色々とだるい (独自のルールとか.まあこれは仕方がないので慣れるしか無い,何回かやると慣れる)
  • 凝ったこと (例えば,コマンドライン引数に応じてファイルの出しわけをするとか) をしようとすると詰む
  • 処理が重い (諦める)

セットアップスクリプトを使う

利点
  • 自由度が高い
    • 例えば上に書いたコマンドライン引数に応じてファイルの出しわけをする (--adminオプションを付けると,管理画面用の雛形が追加されるみたいな) とかが簡単に実現できる
  • ルールに縛られず自分の好きなように作れるので作りやすい
欠点
  • 実行に際して別途セットアップスクリプトの為の処理系が必要
  • 配布が面倒くさい
    • セットアップスクリプトをどこに置くか
    • どうやってインストールするのか
    • 簡単に使えるのか

所感

とりあえず通常の場合は Maven Archetype を使っていくのが良いような気がします.
Java のプロジェクトをやろう!」という人のマシンには間違いなく mvn は入っているでしょうし,なにより archetype配布や実行が楽だからです.Maven Archetype は凝ったことをしない限り戦っていくことが可能です.
配布や実行が楽というのは本当に重要であります.この辺が面倒くさいと誰も使わないし,保守するモチベーションも死んでゆくし,その結果いくら良い雛形であっても滅亡してゆきます.ので,ここは本当に重要.
処理が重いというのはありますが,絶望的に重いわけではないのでここらへんは割り切っていきましょう.そんな頻繁に叩くものでもないので.


Maven Archetype では無理だ!」というレベルの凝ったことをしたくなった時には独自のセットアップスクリプトを用意するくらいで良いという意識になっています.
この場合,セットアップスクリプトをどこに置くかという問題はありますが,そのあたりは GitHub Releases とか,Jenkins の成果物とか,まあいくらでもやりようはあるのかなと思っています.
(雑考: ここらへんに golang を使っていくというアプローチはどうか.ビルド済みのバイナリを然るべき場にソイヤしておくと,各位が適宜エイヤできる気がする)


archetype の作成はだるい,というのはまああるにはあるんですが,セットアップスクリプトを作る場合も結局は面倒なので,この辺は支配的な差にはならないように感じています.


Maven Archetype,最初はその風貌や名前からウッアッという感じになるんですが,慣れると何とかなります.
ひとまずこれで良いんじゃないですかね.