seratch's weblog in Japanese

About Scala, Java and Ruby programming in Japaense. If you need English information, go to http://blog.seratch.net/

Jetty の ServletTester の挙動がおかしいと思ったら自分がおかしかったでござる

Jetty に ServletTester というのがあってですね、生 Servlet のテストをしたいときなんかに結構重宝してたりしたんですよ。

<dependency>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-servlet-tester</artifactId>
    <version>6.1.26</version>
    <scope>test</scope>
</dependency>

こんな感じにテストが書けます。

package example;

import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.mortbay.jetty.testing.HttpTester;
import org.mortbay.jetty.testing.ServletTester;

public class SampleServletTest {

    @Test
    public void testDoGet() throws Exception {
        ServletTester tester = new ServletTester();
        tester.addServlet(SampleServlet.class, "/index");
        tester.start();

        HttpTester request = new HttpTester();
        request.setMethod("GET");
        request.setHeader("Host", "tester"); // should be "tester"
        request.setURI("/index");
        request.setVersion("HTTP/1.1");
        request.setContent("");

        String responses = tester.getResponses(request.generate());
        HttpTester response = new HttpTester();
        response.parse(responses);

        assertThat(response.getStatus(), is(equalTo(200)));
    }

}

ただ、この API、パッと見ておわかりいただけると思うんですが、すごく・・変ですよね・・・。なんというか無理矢理感がすごいというか。

ただ、現実問題として生 Servlet と戦うときにこのテストツールは強力な武器になってくれるので、そこはまあ目をつぶるわけですよ。

org.eclipse になって

で、Jetty が 8,9 で org.eclipse に移管されて、パッケージも org.mortbay.jetty から org.eclipse.jetty になった段階で書き換えられたようです。今回は Servlet 3.1 ではなく Servlet 3.0 をやっていたので 9.0.x を示しています。

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <version>9.0.7.v20131107</version>
    <scope>test</scope>
</dependency>

で、こんな感じに書けるようになったと。

package example;

import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.ServletTester;

public class SampleServletTest {

    @Test
    public void testDoGet() throws Exception {
        ServletTester tester = new ServletTester();
        tester.addServlet(SampleServlet.class, "/index");
        tester.start();

        HttpTester.Request request = HttpTester.newRequest();
        request.setMethod("GET");
        request.setHeader("Host", "tester"); // should be "tester"
        request.setURI("/index");
        request.setVersion("HTTP/1.1");
        request.setContent("");

        HttpTester.Response response = HttpTester.parseResponse(tester.getResponses(request.generate()));

        assertThat(response.getStatus(), is(equalTo(200)));
    }

}

まあ、これでも冗長さはあるわけですけど Request/Response の無理矢理感はなくなって、だいぶマシになりましたね。パッケージやメソッド名なんかも妥当な感じに改善されているんです。「これはいいな、今後は org.eclipse しかメンテされないんだし、こっちに移行しよう!」と思ったのですが・・・

あれ?

実行時間がめちゃくちゃ長くなってしまいました。tester.getResponses(..) のところが遅すぎで普通に 10 秒とかかかっちゃうんですよね。「さすがにそれはおかしいだろう、きっと使い方が悪いに違いない」と思って調べてみたんですが、私が試した限りではどうにもなりませんでした。上記のようなテストであれば 6.x だと一瞬で終わるのですが。

(追記)

という感じで、よくわからないなーと Twitter で日本語で愚痴っていたら Jetty の中の人から SOF で聞いてみたら?とリアクションが。

とりあえず stackoverflow にタグ付きで投稿してみました。

http://stackoverflow.com/questions/20428371/why-servlettester-in-jettty-9-x-is-so-slow

早速、こちらの方から回答がもらえました。要はそもそもが私のポカミスだったと・・

Jetty 9 のサーバは HTTP/1.1 なんだけど

Jetty 9's HttpTester also defaults to HTTP/1.0.

とのことで(HttpTester はリクエストをつくってるやつですね)私のサンプルは HTTP/1.1 指定してるんだから

request.setHeader("Connection", "close");

つけるか HTTP/1.0 でリクエストしないとダメということでした。Connection ヘッダのことがすっかり頭から抜け落ちていました・・。そうか、一定時間で接続切られるまで待っていたのか・・

結論としては、実際は私の確認が甘かっただけで ServletTester はオワコンにはなってなかったです。まずは自分のコードを疑えってことですね。

Typesafe Activator について #scalajp #play_ja

Advent Calendar!

この記事は Play framework 2.x Scala Advent Calendar 2013 の 4 日目です。

http://www.adventar.org/calendars/114

Activator については前に書いたことがある

7 月に Typesafe Activator のテンプレートをつくってみたというブログ記事を書きました。使い方はこの記事の内容で十分かと思います。

http://seratch.hatenablog.jp/entry/2013/07/02/005454

それから半年くらい経ち、色々と変化がありましたね。

Typesafe Activator が OSS になった

8 月に Typesafe Activator の実装が公開されました。

https://www.typesafe.com/blog/typesafe-activator-is-now-open-source

https://github.com/typesafehub/activator

これにより issue を登録してフィードバックしたり、実装を修正して pull request を送ったりといったことが可能になりました。

Typesafe Activator 1.0 リリース

9 月に vesrion 1.0 がリリースされました。この時点で 29 個のテンプレートが登録されていたようです。

http://typesafe.com/blog/announcing-activator-10-create-reactive-apps-in-minutes

ちなみに今日時点での最新バージョンは 1.0.8、登録テンプレートは 41 個ありました。

Typesafe Activator をつくりたい人へ

7 月のブログ記事には「どうやって Typesafe Activator のテンプレートつくるか」が書かかれていませんでした。というのも、こちらのページにある内容だけなので

http://typesafe.com/activator/template/contribute

あえて日本語で説明しなくても、という感じだったのですが、簡単に触れておきます。特に難しいことはないのですが、いくつか注意点を。

activator.properties の name を適当につけない

activator.properties というファイルにメタデータを指定します(なぜ Typesafe Config じゃないの・・とちょっと思った)。前にも書きましたが、この name の文字列がそのまま unique key にされてしまうので、適当につけるのはやめましょう。私はあとから hello-scalikejdbc にしたくなったけど、面倒で scalikejdbc-activator-template のままになっています。。

ライセンス表記が必要

何らかの OSS ライセンスを明記する必要があります。プロジェクトのルートディレクトリに LICENSE または LICENSE.md というファイル名で配置してください。

https://github.com/scalikejdbc/hello-scalikejdbc/pull/1

現時点でリポジトリの移動に対応していない

Typesafe Activator のテンプレートは上記の contribute ページから GitHub リポジトリの URL を指定して追加/更新するのですが、12/4 時点でリポジトリの owner が変わった場合に対応できていません。例えば、私が作っている

https://github.com/scalikejdbc/hello-scalikejdbc

は、以前は https://github.com/seratch/hello-scalikejdbc だったのですが owner が seratch として登録されているので scalikejdbc が owner の URL で更新しようとすると permission がねえぞゴラッみたいなエラーになります。回避策としては古い URL でリクエストすると受け付けてくれるようです。

恒久的には手動対応しかないんですかねぇということで、他に問い合わせ先がなかったので issue にしてみました。(追記)対応してくれました。

https://github.com/typesafehub/activator/issues/180

まとめ

感覚として Typesafe Activator のテンプレートを作ったことによってユーザが増えたとかそういう印象はあまりないのですが zip をダウンロードして初回起動までは特に知識がなくてもできるので Scala 初心者の方に体験してもらうにはよいツールではないでしょうか。ぜひ試してみてください。

明日が空いていますけど・・

誰かいませんか?

http://www.adventar.org/calendars/114

FYI:

いなかったら本当にやりますよ・・

pvm の紹介とその背景について #play_ja

この記事は Play framework 2.x Java and 1.x Advent Calendar 2013 の 2 日目です。元々 12/3 の予定でしたが 12/2 が空いたままで存亡の危機だったので、一日スライドしました。

http://www.adventar.org/calendars/104

pvm とは

今回は pvm(Play Version Manager)について紹介したいと思います。

https://github.com/kaiinkinen/pvm

pvm は nvm の仕様を踏襲した、複数の Play Framework のバージョンを管理するためのツールです。bash で書かれたシンプルなスクリプトで pvm.sh を .bash_profile などで読みこんで使います。

README では $HOME/utils/pvm に git clone する例が紹介されていますが nvm 的にするなら $HOME/.pvm でもいいかもしれません。実際 $HOME/.pvm で運用しても特に支障はないのですが、単に作者の好みですかね。

git clone git://github.com/kaiinkinen/pvm.git .pvm

使い方は一目瞭然なので使い方の解説は省略します。

$ pvm

Play Version Manager

Usage:
    pvm help                    Show this message
    pvm install <version>       Download and install a <version>
    pvm uninstall <version>     Uninstall a version
    pvm use <version>           Modify PATH to use <version>
    pvm run <version> [<args>]  Run <version> with <args> as arguments
    pvm ls                      List installed versions
    pvm ls <version>            List versions matching a given description
    pvm deactivate              Undo effects of PVM on current shell
    pvm alias [<pattern>]       Show all aliases beginning with <pattern>
    pvm alias <name> <version>  Set an alias named <name> pointing to <version>
    pvm unalias <name>          Deletes the alias named <name>
    pvm clean                   Removes non-installed versions from the cache
    pvm clear-cache             Deletes all cached zip files

Example:
    pvm install 1.2.4           Install a specific version number
    pvm use 1.2                 Use the latest available 1.2.x release
    pvm alias default 1.2.4     Auto use the latest installed 1.2 version

bash スクリプトなので Windows では使うことが出来ません。Windows で Play を使っている方、ぜひ Windows 版をつくりましょう!

そもそも必要なの?

「Play って sbt ベースだから play の sbt プラグインのバージョンを各プロジェクトで管理するだけじゃん。こんなの必要なの?」と思われた方、Play 新参者なのがバレてますよ!!!

確かに Play2 にだけ関わっている方であれば不要です。しかし、Play には Plain Old Play Framework ともいうべき 1.2.x がまだ現存しており、かつ世界中でそれなりに稼働し続けているという現実を忘れてはなりません。

http://www.playframework.com/download

こちらは私の開発マシンにインストールされている Play のバージョンです。

$ pvm ls
Available:
     1.2.5       1.2.6       2.1.3       2.2.1
   1.2.5.3       1.2.7       2.1.4

Aliases:
default -> 1.2.7

Current version:
current -> 1.2.7

特に 1.2.5 と 1.2.6 以降は cookie session の互換性がなかったりと断絶があるので 1.2.5 と最新を両方運用しているというケースはまだまだありそうです。Play1 のリリース管理においても 1.2.5 だけは特別扱いしていて 1.2.5.3 というバージョンが出ていたりします。

また 1.3 に向けた開発も続いています。

http://play.lighthouseapp.com/projects/57987/milestones/106971-13

http://play.lighthouseapp.com/projects/57987-play-framework/tickets

Play1 の運用に関わるならば、これからも pvm を利用することはありそうです。

全国の Play ユーザの皆さんへ

Advent Calendar がちょっと寂しい状況になっていますね。ちょっとしたネタでもよいと思うのでぜひお気軽にご参加ください。

Play framework 2.x Java and 1.x Advent Calendar 2013

http://www.adventar.org/calendars/104

Play framework 2.x Scala Advent Calendar 2013

http://www.adventar.org/calendars/114

FYI:

怖い Scala で LT しました #fud_scala

10 月の怖くない Scala 勉強会に対応する形で 11/28 に「怖い Scala」というイベントが開催されました。主催の @yamashiro さん、会場提供いただいたグリー株式会社さん、どうもありがとうございました。

http://connpass.com/event/4112/

これはまさかりを持った @kmizu さんです。このように非常に恐ろしい雰囲気の中、開催された勉強会でした。

LT をしました

ここで「Skinny Framework 進捗どうですか?」というタイトルの LT をしてきました。

Skinny Framework についてはこちらをご覧ください。

http://skinny-framework.org/

https://github.com/skinny-framework/skinny-framework

https://twitter.com/skinnyframework

何か遅かったらしいね?

@yuroyoro さんの ISUCON3 の予選アプリチューニング前状態を Skinny に移植した Scala アプリのスコアがパッとしなくて、LT のときに「先ほど出てきたあまり速くないフレームワークです」と自虐ネタにしましたが

Scala at ISUCON3 2013/11/28 怖いScala @yuroyoro https://dl.dropboxusercontent.com/u/261418/scala_at_isucon3/index.html#/

@yuroyoro さんの資料にもある通り、これに尽きるのかなと思います。

一般的なWebアプリケーション(IO bounds on DB/not CPU bounds)では
Scala(Playframework)に性能上のアドバンテージはない。

Play2 + postgresql-async/mysql-async だったり Finatra + finagle-mysql だったりだと、また違うかもしれません。*1

Skinny は Scalatra(Servlet) + JDBC です。「一般的にはどうなの?」というと、以下の Scalatra とほぼ同等と思っていただければよいと思います。そのうち、このベンチマークにも載せてもらうよう pull request したいですね。

http://www.techempower.com/benchmarks/

Skinny Framework に関わりませんか?

LT の中でも触れましたが Skinny Framework の開発は私一人だけでやり続けない方が良いものになるだろうと思っています。仕事で使ってくださる方々もその方が安心できますよね。

とはいえ、開発を一緒にやってくれる方を探すのはそう簡単ではないので、開発自体は相変わらずほぼ一人という状態が続くかもしれませんが、提案やバグレポートなどをしてくれる方が増えていくと非常に嬉しいです。日本語でももちろん OK なので、お気軽にご連絡ください。

*1:その後@yuroyoro さんが mysql-async でトライされているものの mysql-async はまだまだ buggy なのでうまくいっていないようですが...

Rails4 で response.headers['content-type']

最近 ruby-openid に付属している example の Rails3 アプリをベースに実装を始め、Rails4 にバージョンアップ、微妙な実装箇所を直したり、SReg ではなく AX に対応させるよう修正・・とやっているうちに気がつくとほぼ全部書き換えていた・・!というオチになった私なのですが、その中でも既存の実装を活かし続けていたところでちょっとハマったのでエピソードとして。

response.headers['content-type'] = 'application/xrds+xml'
render :text => yadis

これだと Content-Type が application/xrds+xml に設定されずに text/html だとかになってしまう。正しくはこう。

response.headers['Content-Type'] = 'application/xrds+xml'
render :text => yadis

Rails3 だとどちらでもよいのですが Rails4 から動作しなくなったようです。この記事でいう Rails4 は 4.0.1 です。

元々 Rails3 だったのでバグっていた訳ではなく Rails4 に移行したので挙動が変わってしまったと。そこまでテストで守れるの?と考えると、ちょっとつらい非互換ではありますね。意図とか原因とか調べるべきなんでしょうけど...>誰か

Skinny Framework 導入

を gist に書きました。よかったらご覧ください。はてなブログには gist を埋め込める機能がありますが、コード例のところがきれいに表示できなかったのでリンクを貼るだけにしておきます。

https://gist.github.com/seratch/7382298#file-getting_started_ja-md

GitHub star 数で見る Scala DB アクセスライブラリ事情(2013/10 版)

定期ポストです。

DB ライブラリ

順位 名前 2013/06 2013/07 2013/08 2013/09 2013/10 総増減
1 Slick 613 638 658 692 717 (+25) +104
2 Squeryl 322 329 334 338 340 (+2) +18
3 postgresql-async 159 187 213 227 240 (+13) +81
4 ScalikeJDBC 112 135 141 150 180 (+30) +68
5 Querulous 154 157 158 162 164 (+2) +10
6 scala-activerecord 92 101 104 113 130 (+17) +38
7 sqltyped 109 108 110 119 121 (+2) +12
8 Activate 85 94 99 103 112 (+9) +27
9 SORM 91 95 97 100 102 (+2) +11
10 Prequel 35 37 39 41 44 (+3) +9
11 DataExpress 24 24 27 27 29 (+2) +5
12 ScalikeJDBC-Async - 14 20 27 28 (+1) +28
12 Scala SQL DSL 28 27 27 27 28 (+1) 0
14 ScalaSQL 12 13 13 13 13 (0) +1
15 Scweery 12 12 12 12 12 (0) 0
16 MyBatis Scala 1 3 4 4 7 (+3) +4
17 mirage-scala 4 4 4 5 5 (0) +1
18 shirahae-sql - - 2 2 2 (0) +2

フレームワークの一部

順位 名前 2013/06 2013/07 2013/08 2013/09 2013/10
1 Anorm - - - 3697 3797 (+100)
2 Lift Mapper - - - 717 722 (+5)
3 Spring JDBC Scala 154 168 (+14) 182 (+14) 194 (+12) 212 (+18)
4 Circumflex ORM 136 136 (0) 137 (+1) 140 (+3) 143 (+3)
5 Skinny ORM - - - - 99