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

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

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に送りつける事も可能です.便利ですね.

URIBuilderTinyというのを書いた

URIBuilderTinyというやつを書きました.Maven Centralにもあがっています.盛り上がってまいりました.

http://search.maven.org/#artifactdetails|net.moznion|uribuilder-tiny|2.0.1|


一般的なソフトウェアエンジニア諸氏におかれましてはJavaURIを組み立てたい! みたいな欲求が週に500回くらいあると思いますけれども,そういう時にはURIBuilderを使うかURI Objectを使うかという感じになるかと存じます.


で,URIBuilderはまあ便利なので使うモチベーションが生まれるわけなんですけど,このURIBuilderはApache HttpClientコンポーネントの1つなので,URIを組み立てたいだけなのになぜか俺はHTTP Clientをインストールしている! キエエ! という感じになる事があります*1

加えて,appendPaths(String... paths)のような便利メソッドが実はURIBuilderには存在しないのでウッとなる瞬間があったり,「これはあんま使わんやろ……」というメソッドがいくつかあるというのもあったり……


というわけでこの度URIBuilderTinyというライブラリを作成しました.
特徴としては

  • 依存が少ない (というか実行にあたっての他のライブラリへの依存が無い)
  • appendPaths()のようなチョイ便利なメソッドを足している
  • URIBuilderが実装しているけどあんま使わない(であろう)メソッドは省いている

という感じで自分が使いたいものだけを実装したというライブラリになります.
詳細はドキュメント等を参照ください.

余談ですが,「ホスト名の最後がスラッシュで終わっていたら生成されるURIもスラッシュで終わる」という世話焼き機能が搭載されているなどしています.これ地味に便利なので……


ご活用ください.

*1:とは言え,URIを組み立てたらHTTP Clientでリクエストを飛ばしたりするだろ普通は,というのはありますが

命名の話

命名の話をしました.1時間位でなんとか間に合わせで書いた資料です.
よろしくお願いします.

www.slideshare.net


あと,例えばメソッド名で"get"と"retrieve"と"fetch"をどう使い分けるか,みたいな話題が出て,
僕あたりは

  • getは単純なゲッター的なものに使う
  • retrieve は DB にアクセスして値を取ってくるものに使う
  • fetch は何らかごちゃごちゃ処理をして (API 叩くとか) 所望の値を取ってくるものに使う

という風な使い分けの話をしました.そういったルールが各々の人の中にはあります.
ここらへんのルールというのは個人が好き放題やっても無力なので (というかノイズたりえるので) プロジェクトの人間たちが話し合ってすり合わせる必要があります.
とは言え,いちいち些細な命名の問題について話し合っていくのはだるいので日常的なコードレビュー等でコモンセンスというか文化みたいなものを育てていくのが重要だと思っています.

人間には名前を考える能力というものがあるので積極的に考えていくと良いでしょう.考えると得です.

こちらからは以上です.


以上と言いましたがその後「変数名に ? とか ! とか使えると便利だよね〜」という話があって,そう言えばそうですね,便利です,という認識を改にしました.is とか付けるよりもスマートですよね.
Ruby とか LISP とかはここらへん使えて大層良いのですが,なかなかそういった命名を許している言語は多くないですね.ウムー

MySQL の lower_case_table_names について,テーブル名とデータベース名の中の大文字小文字について

MySQL には lower_case_table_names という変数があって,これはテーブル名の大文字小文字を区別するかどうかというのを設定するパラメータなわけですが,その詳細は以下のようになっています (参照: MySQL :: MySQL 5.6 Reference Manual :: 9.2.2 Identifier Case Sensitivity).

Value 説明
0 大文字・小文字を区別してデータベース名やテーブル名をストアする.これらの名前の比較についても大文字・小文字を区別する.MySQL のサーバが動作する OS のファイルシステムが大文字と小文字を区別しない場合 (例えば OS XWindows),この値に設定すべきではない.そうしたファイルシステム上でこの値を0にして,なおかつ MyISAM のテーブル名に対して大文字小文字を混ぜてアクセスするとインデックスがぶっ壊れることがある.
1 テーブル名やデータベース名をストアするときにすべてを小文字に丸める.名前の比較については大文字・小文字を区別しない.
2 テーブル名やデータベース名をストアするときはそのままストアする (つまり大文字・小文字情報を保持したままストアする).Lookup 時はこれらの名前が小文字に変換され,名前の比較については大文字・小文字を区別せずに行う.なおこの機能は,大文字・小文字を区別しないファイルシステムでのみ機能するInnoDB のテーブル名は lower_case_table_names=1 に設定した時のようにすべて小文字で保存される.

手元でデフォルト値を調べてみたら,CentOS に入っている MySQLlower_case_table_names は 0,OS X では 2,更に Windows では 1という風になっていてマジカオス!! という感じで *1,実際に Windows 上で mysqldump で吐いた dump を LinuxMySQL に食わせたら "duplicated key" みたいな感じで死ぬ,みたいな事が起こりました.


これを避けるためには単一のプラットフォーム上で開発すれば良いわけですが,皆さんにおかれましては OS X で開発して Linux のプロダクション環境にデプロイするみたいな事も多いでしょうし,Windows での開発を貫く開発メンバーも一定数存在していることと存じます.


というわけで対策をする必要があります.公式のドキュメントにも載っていますが,取るべき方法は3つあります.

1. lower_case_table_names=1 をすべてのシステムで利用する.SHOW TABLES や SHOW DATABASE を叩いた時に,もとの大文字・小文字が区別された名前を見れないという欠点がある.
2. OS XWindows では lower_case_table_names=2 を使用する.その他のシステムでは0を使用する.SHOW TABLES や SHOW DATABASE を叩いた時でも大文字と小文字が区別された名前を確認することが出来る.一方で OS XWindows 上で,ユーザのステートメントがデータベース名やテーブル名をひくときに大文字と小文字が正確に区別されているかを確認する必要がある.例外として,InnoDB を使っていてなおかつこれらの問題を回避したい場合は,(この方法を使うよりも) すべてのプラットフォームで lower_case_table_names=1 を強制したほうが良い.
3. データベース名やテーブル名には常に小文字を使う.


3 の「データベース名やテーブル名には常に小文字を使う」というのがまあてっとり早くて良いと思います *2
それに加えて1の方法を採って,lower_case_table_names=1 を設定し,小文字の利用をシステム側で強制しておくと事故が起こりにくくなって良いのではないかと思った次第です.


ちなみにlower_case_table_names=1 にしたい時は古いデータベースをコンバートする必要があるので注意.行動が必要になった際はドキュメントを読みましょう.
https://dev.mysql.com/doc/refman/5.6/en/identifier-case-sensitivity.html

結論

とにかくデータベース名やテーブル名には大文字と小文字を混ぜない.小文字だけでやっていく,という意識が重要そう.併せて lower_case_table_names=1 を設定する.

あと,根本的な話として開発環境と本番環境はできるだけ近づける必要がある.WindowsMac で開発して Linux の本番環境にデプロイとか,その逆とかをしていると MySQL に限らず問題が起こる可能性が高まるので何とかしましょう.現存するソリューションとしては仮想マシンなどがあります.

その他

  • InnoDB だったら,大文字小文字を区別しないファイルシステムであっても lower_case_table_names=0 を使っても問題ないのだろうか?
  • 大文字小文字を区別するファイルシステムlower_case_table_names=2 にした時は,lower_case_table_names=0 に fall back される
  • 一部のドキュメントの意味がよくわからなかった……






*1:とは言えこれは仕方がない

*2:とはいえ色々あってそうも出来ないこともある

donovan という1枚 java ファイルを書けばウェブアプリを立ち上げられる WAF を書いた

※ WAF: Web Application Framework


表題の通りです.Maven Central にも上がっています.


avans という tokuhirom さんが書いた WAF があり,Sledge や Amon2 の流れをくむシンプルで良いフレームワークがあって,最近はもっぱらそれでウェブアプリケーションを書く日々が続いているわけですが,
avans でウェブアプリ―ケーションを立ち上げるには class を真面目に定義したり設定ファイルをちゃんと書いてやる必要があり,もう少しゆるふわ,というか雑にやりたいな〜という欲求が生まれる瞬間があります.

そうした思いから,この donovan という WAF を作成しました.
ご多分に漏れず,avans の影響をバリバリ受けているというか,コードの多くを参考にしています.


簡単に説明すると

  • 組み込みの Servlet Container (Embedded Tomcat or Embedded Jetty) により動作する
  • ディスパッチャとそのパスの動作を lambda によって一緒に書ける
  • java のファイルを1枚書けば動く
  • 割と依存が少ない

という特徴を持ったミニマルな WAF になります.


donovan で Embedded Jetty を使った例を書くと,

@Slf4j
public class App {
    public static void main(String[] args) throws Exception {
        DonovanJetty dj = new DonovanJetty()) 
        dj.get("/", (c) -> {
            return c.renderJSON(new BasicAPIResponse(200, "hello!"));
        });

        dj.start();
        log.info("{}", dj.getURL());
        dj.join();
    }
}

と書いて起動してやると*1,「ルートを GET で叩くと "hello!" が返ってくるというようなアプリケーション」をザクッと書くことが可能となります.
各エンドポイントは donovan からコンテキストが渡され (色々な情報が入っている),WebResponse (webscrew が提供する interface) を返すという処理を実装すれば良いという感じです.
詳細は README.mdjavadoc をご覧ください.


こうした感じで,donovan を使うとゆるふわにウェブアプリをガツンと立ち上げることが可能となります.
主に API のモックや,ちょっと動作を確認したいときなんかに使う為に作成した WAF なので本チャンの環境で使うようなものではございませんのでやめたほうが良いでしょう *2.まあ小さいものならいけそうではある *3

ご利用くださいませ.

*1:djという変数名が良いですね

*2:というかこれでちょっとでもデカいもの書こうとすると設計が破綻する気がする

*3:spark なんかは似ている思想っぽいし……まあとはいえ組み込み servlet container ではないので微妙なところ http://sparkjava.com/