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

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

gimei-java 作った

世は空前の gimei ブームです.この前 go 版が出ましたね.
というわけで,というわけではなく,業務で必要だったので gimei-java を作ってしかるべきところ (つまりmaven central) にあげました.


Ruby には gimei という gem があり,

gimei は、日本人の名前や、日本の住所をランダムに返すライブラリです。テストの時などに使います。似たようなライブラリにfakerがあります。fakerはとても優れたライブラリで、多言語対応もしていますが、ふりがな(フリガナ)は流石に対応していません。gimei ふりがな(及びフリガナ)に対応しています。

というやつで,強いんですが,Java には存在しておりませんでした (もちろん Faker はある).

そんな折,大量にテストデータを作る必要が出てきて,僕は「テスト太郎」や「テスト花子」などという架空人物の名前を心をこめて考えてやっていたのですがそんな生活にももちろん限界が来てしまいます.


というわけでこの度 Java 版の gimei を作成・リリース致しました.
快くオリジナルの人名・住所のデータを使わせてくださった @ さんありがとうございます.


gem の gimei と同等な機能はほぼ揃えています.
使い方は README 等を読んでもらうとして,gimei-java にはオリジナルにはない tarohanako,加えて noun という機能が追加されています.
それぞれ何かと言うと「○○太郎」「○○花子」 (○○にはそれぞれランダムな名詞が入る),そしてランダムな名詞を出力するという機能になっています.

こんな感じ:

Taro taro = Gimei.generateTaro();

taro.kanji();    // => "ハム 太郎"
taro.hiragana(); // => "はむ たろう"
taro.katakana(); // => "ハム タロウ"

Hanako hanako = Gimei.generateHanako();

hanako.kanji();    // => "パソコン 花子"
hanako.hiragana(); // => "ぱそこん はなこ"
hanako.katakana(); // => "パソコン ハナコ"

Noun noun = Gimei.generateNoun();

noun.kanji();    // => "関東電化工業"
noun.hiragana(); // => "かんとうでんかこうぎょう"
noun.katakana(); // => "カントウデンカコウギョウ"

これらの機能は実は便利で,「○○太郎」や「○○花子」がテストデータに入っていると,それだけで役所感が出てくるのでカタい仕事をしているという気分に浸ることが可能です.あと男女の見分けが一瞬でできる.

名詞をランダムに出す機能は,個人的に架空の店舗名などを生成する必要があったため「<名詞> + 店」みたいな風に使えると便利かな〜と思って付け足しました.便利.

これらの機能で使っている名詞データのオリジナルはnaist-jdicで,そこから名詞・一般と名詞・固有名詞のみを抽出し,更にそこから1万件に絞り込んだというスタイルになっています.


もしも欲しい太郎や花子がございましたら,名詞のyamlにその名詞データを突っ込むだけなのでパッチを送って来てもらえればと思います.



以上です.ご利用下さい.

STDIN経由で入力を受け取って1秒あたりのスループットを取れるpersecというのを書いた

表題のやつです.便利っぽかったのと書きたかったという理由からgoで書いています.

例えばアクセスログのようなものがあった時,「1秒間に何行ログに書き込まれているか」が分かれば秒間のアクセス数を求めることが可能となります.これはそういうことをする為のツールとなります.
persecを一言で言うと,「1秒間に何行やってくるか」をカウントするコマンドです.

$ tail -F nankano.log | persec

という風に使ってやると,persecはteeの様にtail -Fの内容をそのまま出力しつつ,行数をカウントして一定周期ごとにそのスループットを出力します.末尾に雑に噛ませておくとスループットが取れる.

デフォルトだと,persecは60秒ごとのインターバルでスループットをSTDOUTに吐き出します.この場合は60秒間分の行数をカウントしておいて,それを60で割ったものを1秒間あたりのスループットとして扱います.
インターバルは--deltaスループットの出力先は--outというオプションでそれぞれ指定することが可能です.また,--noteeオプションを指定すると,受け取った内容をteeの様にフォワードしなくなります.

加えて--patternというオプションによって,カウントの対象とする行を絞り込むことが出来ます.ここにはgoで利用可能な正規表現を突っ込むことが出来ます.例えば,yyyy-mm-ddから始まる行だけをカウント対象にしたい場合は--pattern="^[0-9]{4}-[0-9]{2}-[0-9]{2}"というふうに指定してやるとそのような感じになります.

--helpで詳細が見れますから,そちらもご確認ください.


シェルスクリプトでも頑張ればこういうことが出来るような気もしたんですが僕にはその力が足りなかった!
というわけでどうぞ御利用ください.


余談ですがテストをどう書けば良いかわからなくて,結局シェルスクリプトによるE2Eテストになってしまった……

java-db-transaction-managerが出ていた

大昔の話ですが,java-db-transaction-managerというのを書いて,リリースしていました.

PerlのTransaction ManagerであるDBIx::TransactionManagerJava移植版です.シンプルなやつが欲しかったので.


機能としてはDBのtransactionに必要な機能であるbegin,commit,rollbackを提供しています.
入れ子になったtransaction内で既にrollbackされているのにも関わらずcommitが発行された時は例外が上がります.普通な感じですね.
try-with-resourcesを利用することも可能で,もし明示的にcommitもしくはrollbackが発行されないままそのスコープ外に出ると自動的にrollbackを発行するというような挙動になっています.

加えて,アクティブなtransactionのトレース (現在のtransactionのみ,あるいは全てのtransactionについて) を取るということも出来ます.便利!
ところでJavaでLLの様にカジュアルにスタックトレースの情報を取ろうとするとまあまあハイコストで困ってしまう,というかパフォーマンスに支障が出るわけですけれども,それを何とかすべくこのライブラリではJDKのprivateなAPIをリフレクションで呼び出すという力技で解決しています.そうすると速い.ここらへんは
tokuhirom/caller · GitHub
を参考にしました.


御利用ください.
あ,念のため言うとスレッドセーフではないです.

tinyormで任意のcolumn名を指定できるようになってた

MySQL の lower_case_table_names について,テーブル名とデータベース名の中の大文字小文字について - その手の平は尻もつかめるさ

こういう話があり,column名を小文字オンリーのsnake_caseでやりたかったりすることがあります.
今までのtinyormではRow Classのfield名がそのままcolumn名として扱われるため,Javaの一般的なコーディングスタイルではcamelCaseしか扱うことが出来ませんでした (field名をsnake_caseにすると回避可能ではありますが,不格好なスタイルになります).


というふうな背景からパッチを送った所,このあたりで取り込まれ,利用可能となりましたのでお知らせします.
以下のように使うことが出来ます *1

@Value
@Table("member")
@EqualsAndHashCode(callSuper = false)
public MemberRow extends Row<MemberRow> {
    @PrimaryKey
    @Column("member_id")
    private long memberId;
    @Column("member_name")
    private String memberName;
}

便利ですね.

*1:memberってテーブルなんだからcolumn名にmemberってprefixつけねーだろ普通,というツッコミは脇にのけてください

npmとかbowerとか使ってるプロジェクトでEclipse使うと破滅するんだけど〜って人

npmとかbowerとかによって大量のjsファイルがディレクトリ中に含まれているプロジェクトでEclipse使うと破滅するんです.わかるでしょう.破滅するんですよ.滅亡です.
何故かと言うと,EclipseはWorkspaceをビルドする時にその大量のjsファイルに対してvalidationを走らせるからです.このvalidationがマジで重くて容易くハングします.もう駄目だ.


最近のプロジェクトでここらへんのjsの便利ツールを使わないはずが無いのでなんとかする必要があります.
そこで僕ってばIntelliJを使うことにしたわけなんですが,ちゃんとなんとかする方法もあります.
どうするかというと,プロジェクトの.projectファイルをエディッタで開いて,

<buildCommand>
    <name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
    <arguments>
    </arguments>
</buildCommand>

となっている所をまるっと削除してやるとよろしい.どうせEclipseでjsをアレやコレやすることもないでしょう? することがある人は頑張ってください.

Eclipse building workspace hangs after importing existing maven project because of JavaScript validation - Stack Overflow

ここに書いてました.最高.

Jettyを使ったリバースプロキシ構成のときに本当のアクセス元の情報が知りたいんですけど〜って時

Jettyを使ったリバースプロキシ構成をやっている時に,プロキシではなく本当のアクセス元の情報を知りたいという事があります.例えばHttpServletRequest#getRemoteAddr()とかで取りたい,みたいな.というかほとんどの場合でそういった欲求があります.
そういった時にどうするか,みたいなのを調べたのでメモを記します.なおJettyのバージョンは9です.


プロキシの方は当然ながらX-Forwarded-*系のヘッダを正しく取り扱える様に編集しておきます.
Nginxとかだとこんな感じになるでしょう.

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}


Jettyの設定の方は,デフォルトのjetty.xml

<!-- Uncomment to enable handling of X-Forwarded- style headers
<Call name="addCustomizer">
    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
</Call>
-->

コメントアウトされている所のコメントアウトを外してやると良いです.でもってJettyを再起動.
このForwardedRequestCustomizerが何をする君かというと,

  • X-Forwarded-Host
  • X-Forwarded-Server
  • X-Forwarded-For
  • X-Forwarded-Proto

のヘッダを見て,それを処理して Servlet の Request ヘッダをよしなにしてくれる君です.
HttpServletRequest#getRemoteAddr() がリバースプロキシの IP アドレスではなく,リアルのリクエスト元の IP アドレスを返してくるようになったりします.
詳しくはこちらを参照して下さい.
http://download.eclipse.org/jetty/9.2.10.v20150310/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html


あと,
Plack::Middleware::ReverseProxy でリモートホストを確認する理由 - blog.nomadscafe.jp
というような話題があり,こうした対応が必要となるかも知れません (とは言えJettyが使うポートが外に露出しているというケースはあまり無いと思いますが……).
そうした場合どうするかと言うと,jetty-http.xmlとjetty-https.xmlのそれぞれに

<Set name="host"><SystemProperty name="jetty.host" default="127.0.0.1" /></Set>

と書いてやると良い.こうすると,このJettyに対してはlocalhostからしかアクセス出来ないようになります.
まあ,やっとくと良いでしょうという感じはします.


なお余談ですが,Jettyのリバースプロキシ環境下でのフォワードについて調べると

<Call name="addConnector">
    <Arg>
        <New class="org.eclipse.jetty.nio.SelectChannelConnector">
            <Set name="port">8080</Set>
            <Set name="forwarded">true</Set>
        </New>
    </Arg>
</Call>

とすると良いというような情報に行き着くと思うんですが,これは古いJetty (6とか) のための情報で,
現時点で最新のJetty 9などでは利用不可能な情報です.ご注意ください.

Java でテストカバレッジを取る (JaCoCo編)

一種の指標になるので,なんだかんだでテストカバレッジは取りたくなります.

Javaでそれをどうやるかをサッと検索すると,Coberturaを使う方法とJaCoCoを使う方法が引っかかると思うんですが,Coberturaの方はJava8のコードが含まれているとJavaNCSSの兼ね合いで発狂して使えなくなったり,Mavenのtestライフサイクルにfindbugscheckstyleを含めると使えなくなったりと色々不便なので,JaCoCoを使う方法でやることになっていきます.

Mavenでどうやるかというと,pom.xml

<plugin>
	<groupId>org.jacoco</groupId>
	<artifactId>jacoco-maven-plugin</artifactId>
	<version>0.7.4.201502262128</version>
	<executions>
		<execution>
			<id>prepare-agent</id>
			<goals>
				<goal>prepare-agent</goal>
			</goals>
		</execution>
	</executions>
</plugin>

という風に追記してやると良いってcoveralls-maven-pluginに説明されていましたのでそのようにやります.

そして

$ mvn clear test jacoco:report

などとしてやると,target/site/jacoco 以下にカバレッジレポートが出力されます.

f:id:moznion:20150425164600p:plain

コードレベルのカバーレポートも出て可愛い.

f:id:moznion:20150425164624p:plain

そしてこの結果をcoveralls-maven-pluginを使ってcoverallsに送りつける事も可能です.便利ですね.