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

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

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

Maven Archetype で文字列を置換したりする

Maven Archetypearchetype を作るとき,文字列を置換したくなることがあります.
例えば $artifactIdfoo-bar と入っている時にこれを foo_bar という風に s/-/_/g したくなる事などがあるでしょう.世の中色々あるのです.

そういう時は以下のように書いてやると良い.

${artifactId.replaceAll("-", "_")}

こういう感じで普通に replaceAll() 等の String のインスタンスメソッドを呼び出すことが出来るので便利.


でもって pom.xml

#set($replaced = $artifactId.replaceAll("-", "_"))

とか書いてやると,archetype 内で $replaced という変数が置換後の内容として使えるようになるので便利!!


現場からは以上です.

Maven Archetype で ## がコメントとして扱われるのでなんとかする

Maven Archetypearchetype を作る時,archetype に含めるファイルの中に ## が入っていると行のそれ以降がコメントとして扱われる為,内容が抜け落ちてしまうというような事があります.
例えば Markdown 形式のファイルなんかを archetype 内に含めていると悲惨で,

## My Awesome Project!

という風に,見出しを期待して ## から始める文を書いてしまうと,これはコメントとして扱われ空行として出力されることになります.
これはMaven Archetype が内部で使っている Apache Velocity が ## をコメントとして扱う為です.ジーザス.


こうした時にどうやって archetype 中のファイルで ## を使うのか,という話ですけれども,archetype-resources/pom.xml の先頭に #set($sharp = '#') と書いてやるとよろしい.


例;

#set($sharp = '#')
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
</project>

こうすると,$sharp という変数が # として扱われるようになります.
そして ## が含まれるファイルはこのように書き換える;

${sharp}${sharp} My Awesome Project!


見た目は悪いがコイツは動く.