2015年11月27日金曜日

StrongLoopを使ってみる(LoopBack)

StrongLoopは、Node.js, Expressに対してProcess Manager, LoopBack, Enterprise Connectors, API Gateway, Arc Console, Monitoring, Profiling, Tracingという機能を加えたもの。今回は中心となるLoopBackを使って、RESTアプリケーションを作ってみる。

StrongLoopのインストール方法はこちら。今回試してみる手順はこちら

1. コマンドを実行するとYeomanを使って雛形が生成される。
$ slc loopback

2. モデルを作る。
$ slc loopback:model

3. モデル名を入力してオンメモリDB(memory)とPersistedModelを選択する。REST公開はY、plural formはそのままEnter, common modelを選択する。

4. プロパティーはstring型のnameと言う名前で定義する。

5. 稼動させる。localhost:3000/explorerにアクセスするとAPI一覧を見ることができる。
$ node .
$ curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" \
      -d '{"name":"foo"}' "http://localhost:3000/api/CoffeeShops"
$ curl -X GET --header "Accept: application/json" "http://localhost:3000/api/CoffeeShops"
対応しているデータソースに接続する方法はこちら。2015/11時点の最新版でslc loopback:datasourceを実行したところ以下が出力された。
  • In-memory db (supported by StrongLoop)
  • Email (supported by StrongLoop)
  • MySQL (supported by StrongLoop)
  • PostgreSQL (supported by StrongLoop)
  • Oracle (supported by StrongLoop)
  • Microsoft SQL (supported by StrongLoop)
  • MongoDB (supported by StrongLoop)
  • SOAP webservices (supported by StrongLoop)
  • REST services (supported by StrongLoop)
  • Neo4j (provided by community)
  • Kafka (provided by community)
  • SAP HANA (provided by community)
  • Couchbase (provided by community)

2015年11月22日日曜日

EclipseLinkを使った実装例

このExampleを動かしてみる。DBをRESTで公開するというもの。
http://wiki.eclipse.org/EclipseLink/Examples/JPARS/Simple
https://wiki.eclipse.org/EclipseLink/Release/2.4.0/JPA-RS

実装については最後の方で説明する。まずはサンプルを動かしてみた記録。

基本的にこのページに書いてある通りに進めていくがせっかくなので最新版を使いたい。GlassFishは最新版のバージョン4系を使いたかったが、JDBCコネクションプールの作成でこのエラーが起きて先に進めないので諦めた。代わりにPayaraというサーバーをはじめて使ってみる。

Payaraのインストール
今回は、4.1.1.154 Full JavaEEをインストールする。$GLASSFISH_HOME/glassfish/modulesのjarの置き換えは不要だった。

②Examplesをgit clone
git clone git://git.eclipse.org/gitroot/eclipselink/examples.git

③Payaraのデータソース、JDBCリソースの設定
コンソール画面から、Resources > JDBC > JDBC Connection Poolsと進んでいき設定。GlassFishのバグが修正されており、先に進むことができる。$GLASSFISH_HOME/glassfish/domains/<your_domain_folder>/lib/extにはJDBCドライバーjarを配置しておく。その他設定値は以下の通り。driverType=4を忘れないように。DB2環境はこちらを使った。環境構築時の記録はこちら
  • Resource Type=javax.sql.DataSource
  • Datasource Classname=com.ibm.db2.jcc.DB2DataSource
Additional Propertiesは以下の通り
  • serverName=localhost
  • portNumber=50000
  • databaseName=任意(SAMPLEでもOK)
  • serverName=任意
  • password=任意
  • driverType=4

④EclipseでMavenプロジェクトのインポート

⑤Eclipseでサーバーの追加
PayaraはGlassFishとの互換性があるとのことなので、GlassFish4サーバーとして追加する。

⑥student.webのデプロイ
Eclipse上から普通にデプロイする

⑦Google ChromeにPostmanをインストールしてリクエストを送信
http://localhost:8080/student.web/persistence/v1.0/jpars_example_student/metadata
POSTするときはContent-Type=application/jsonを付けること

以上で、サンプルが動くところまでは無事確認できた。この後は実装についてだが、てっきりJAX-RSのアノテーションが出てくるのかと思いきや存在せず、student.webプロジェクトはWeaverBeanというクラス1つだけと大変シンプル。

説明としては、こちらが分かりやすかった。
http://blog.bdoughan.com/2013/04/introducing-eclipselink-jpa-rs.html

ドキュメントをほとんど見つけられなかった。


JPA実装の違い

JPA(Java Persistence API)の実装には複数あるが、どれを使うのが良いのだろうか。
Hibernateは独自機能が多そうなので、ずっと使い続けることができる状況なら良さそうだが、そうでない場合はEclipseLinkを使っておくのが無難っぽい。OpenJPAはあまり開発が活発ではないようで、JPA 2.1に対応できていない(私は2.1の新機能を使うほどJPAを使いこなすことはないと思うけど、開発が活発な方を選んでおきたい)。他には、あまり情報が集められないけどDataNucleusが面白そう。

名前 開発元 仕様 備考
EclipseLink Eclipse
Foundation
JPA 2.1, 2.0 JPA仕様の参照実装
Hibernate RedHat JPA 2.0, 2.1
OpenJPA Apache
Foundation
JPA 2.0
JPA for WebSphere Application Server IBM JPA 2.0, 2.1 JPA 2.1実装はEclipseLinkベース、JPA 2.0実装はOpenJPAベース(WebSphere Liberty Profileの場合)
TopLink Oracle JPA 2.0 JPA 2.1サポートはJavaEE7に含まれるためパッチとして提供


2015年11月21日土曜日

Dockerを使ってMac上にDB2境を準備する

DB2 Express-Cという無償で使えるDB2があるが、残念ながらMacはサポートされていない。
http://www-01.ibm.com/software/data/db2/express-c/download.html

そこでDockerを使って環境を作る。使ったソフトウェアは以下の通り。

  • Docker Machine 0.4.1
  • Docker 1.8.3
  • VirtualBox 5.0.10
インストール手順はいろんなところに書いてあるので割愛。VirtualBoxの仮想マシンを作成が完了した後はこんな感じ。
~ % docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL   SWARM
default            virtualbox   Stopped
~ % docker-machine start default
Starting VM...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
~ % eval "$(docker-machine env default)"

ここから先がDB2に関係する部分。使うのはibmcom/db2express-c。手順は以下の通り。docker pullで取得するサイズが大きい(1.7GB)のでしばらく時間がかかる。
~ % docker pull ibmcom/db2express-c
~ % docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ibmcom/db2express-c   latest              2abb3b6fc22c        6 months ago        1.705 GB
~ % docker run -it -p 50000:50000 -e DB2INST1_PASSWORD=db2inst1-pwd -e LICENSE=accept ibmcom/db2express-c:latest bash

ここまででDockerコンテナにログインできる。Macからコンテナに50000番ポートで接続するためにはVirtualBox上でのポートフォワーディングも必要。lsofでListenしていることを確認できる。
~ % VBoxManage controlvm default natpf1 "db2_pf,tcp,127.0.0.1,50000,,50000"
~ % lsof -P -i -n | grep 50000

ここまででMacからコンテナに50000番で接続できるようになった。後はDB2側で必要な設定をすればOK。ibmcom/db2express-cに書いてある通りサンプルDBを作ったり、デーモンとして起動したりできる。

サンプルDBの作成
$ su - db2inst1 $ db2start $ db2sampl

デーモンとして起動
docker run -d -p 50000:50000 -e DB2INST1_PASSWORD=db2inst1-pwd -e LICENSE=accept ibmcom/db2express-c:latest db2start

テスト用途ならコンテナの再起動でデータが消えても問題ないことが多いと思われるのでここで作業を終わりにするが、永続化が必要な場合は別途設定が必要。

2015年11月16日月曜日

ASMのドキュメントを読む(Core API - Methods - Interfaces and components前半)

前回の続き。今回からASMについて。

ASMではVisitorパターンを使って、バイトコードを生成したり変更したりする。コンパイル後のクラスファイル群は、クラスがあったりメソッドがあったりアノテーションが付いていたりと複雑なツリー状の構造をしているので、ツリーの中のどの要素をどう操作するかを記述していくことになる。

Visitorパターンでは複数の要素を巡って処理するものだが、ASMではVisitorクラスのコンストラクタに別のVisitorオブジェクトを登録するところがポイント。インスタンスを作る時にVisitor1→Visitor2→Visitor3のようにVisitor同士を一方向に繋げるようになっている。ClassReaderやClassWriterのような入出力もVisitorでできているので、既存のクラスファイルを読み込んで、複数箇所を変換して、出力するという一連のバイトコード操作の処理フローを作ることができる。

MethodVisitorの場合、プログラマーの責任において次の順番で呼びだすことが定められている。
visitAnnotationDefault?
( visitAnnotation | visitParameterAnnotation | visitAttribute )* ( visitCode
( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn | visitLocalVariable | visitLineNumber )*
visitMaxs )? visitEnd 

ややこしいことに、ClassWriterで出力するためには、フレームとローカル変数、オペランドスタックのサイズを計算する必要がある。ASMに自動計算させることもできるが10%〜2倍程度遅くなる。new ClassWriter(ClassWriter.COMPUTE_FRAMES)を指定してもvisitMaxs()メソッドの呼び出しは省略できないことに注意。引数は無視されるのでvisitMaxs(0,0)でOK

ASMのドキュメントを読む(Core API - Methods - Structure)

Javaバイトコード操作のためのライブラリであるASMのガイドのメモの第1弾。
最新版はバージョン5系だが、ガイドは4のものしかない。
http://download.forge.objectweb.org/asm/asm4-guide.pdf

今回はASMまでは言及せずに、JVMの実行モデルについての概念の整理。
  • 各スレッドは実行スタックを持っている(ヒープはスレッドが共有する)
  • 実行スタックには複数のフレームから成る(フレーム1つが、1回のメソッド呼び出しに相当する)
  • フレームはローカル変数部とオペランドスタックから成る(ローカル変数にはインデックスが付いたリスト、オペランドスタックはバイトコード命令のためのスタックである。
  • ちょっと複雑だが、実行スタックの中にオペランドスタックが入っていることになる。
  • バイトコード命令は、opcodeとopcodeごとに決まった数の引数から成る(opcodeは命令の内容を識別するコードで1バイトで表現される。だから「バイトコード」と呼ぶ。)
  • オペランドスタックにはバイトコード命令そのものと、そのバイトコード命令で使うデータも格納する(つまりデータの格納場所としてはローカル変数部とオペランドスタックの2箇所がある)
  • バイトコード命令には、ローカル変数部とオペランドスタックの間でデータを移動させる命令と、オペランドスタックの中だけで操作する命令の2種類がある(あらゆるメソッドが1フレームという単純なルールで表現できるのはちょっと不思議な感じがする)
Javaはオブジェクト指向言語なので、メソッド呼び出し=メッセージ・パッシングである。あるインスタンスメソッドを呼び出す場合、ローカル変数部にはthisと引数が格納される。実際は、ローカル変数はthisのインスタンスはヒープに存在してローカル変数部にはポインタが入っているだけ。longやdouble型の値は、2スロット分を使って格納する(つまり1スロットは4バイト?)。

ASMのガイドにはいろんな例が載っている。例えばpkg.Beanクラスのfというint型フィールドのgetterは以下のようになる。
ALOAD 0・・・ローカル変数部に格納されているthisをオペランドスタックに積む。
GETFIELD pkg/Bean f I・・・pkg.Beanクラスのオブジェクトのfというフィールドのint型の値を取得してオペランドスタックに積む。thisはpopされる。
IRETURN・・・オペランドスタック上のint型の値をpopしてメソッドの戻り値として返す。

fという名前は定数プールから名前解決される。ここを見るとバイトコード命令の実行前後でオペランドスタックの状態がどのように遷移するかがわかりやすい。

次回からASMでバイトコードを扱う方法に入っていく。

2015年11月15日日曜日

javax.annotation.processing

アノテーションを使って処理するための機能が入っているのがjavax.annotation.processing。アノテーション処理をラウンドという単位に分けて段階的に処理を行う。各ラウンドではあるプロセッサーに定義された処理を行う。プロセッサーはアノテーションをもとにJavaソースコードやXMLファイルなどを生成する。ラウンドというのは生成されたJavaソースコードをさらに別のプロセッサーにかけることを意図したもの。普通はjavacの実行時にプロセッサーを実行する。
https://docs.oracle.com/javase/jp/8/api/index.html?javax/annotation/processing/Processor.html

java.lang.instrument

JVMにはインストゥルメンテーションという機能があって、実行中にバイトコードを書き換えることができる(元々は実行中のプログラムの計測のためのものらしい)。
https://docs.oracle.com/javase/jp/8/api/java/lang/instrument/package-summary.html

 プログラマーがバイトコードを書き換えるためには、エージェントというものを作る。エージェントを書き換え対象のJVMに適用するには2通りの方法がある。
  1. JVMの実行時に-javaagentオプションによってエージェントJARを指定する。-javaagentは複数指定できる。
  2. すでに起動済みのJVMに対してエージェントを適用する場合は、別JVMとしてエージェントを起動して起動済みのJVMにアタッチする。jconsoleがこちらのパターン。Attach APIというものを使うようだが、これは開発ベンダー依存APIなので注意。
バイトコードを書き換えることができるので、普通のプロダクトではできないようなある意味、黒魔術っぽいことができるようになる。このインストゥルメンテーションを使っている有名なプロダクトを調べてみた(ドキュメントで調べただけで実際には1つも試してはいない)。
  • JRebel・・・サーバー上にデプロイするアプリケーションのように長時間起動するアプリケーションを開発中にソースコードを書き換えた時にIDEがコンパイルしたバイトコードを使ってサーバーが使っているバイトコードを置き換えることで、リアルタイムに変更を反映できる。いわゆるホットスワッピングとかホットコード置換とかホットデプロイと呼ばれるもの。デバッガーがコードを変更するのと似ているが、適用できる範囲が違うらしいSpring-Loadedも似ている。販売元による比較がこちらにある。Seaser(S2Container)はDIコンテナだからエージェントを使ったアプローチではないけど実現しようとしていることは似ている。
  • NewRelic・・・JVMに限らずソフトウェアの監視を行うサービスだが、JVMアプリケーションを監視する場合は、-javaagentで指定する。ログを監視サーバーに送るのかな。
  • Lombok・・・ お決まりの「ボイラープレート」コード削減することができる。EclipseなどのIDEに導入するときに-javaagentで指定する。エージェントだけでなくjavax.annotation.processingも使用して実現している。
  • JMockit・・・テスト時のモックを作るためのツール。
  • JaCoCo・・・テスト時のカバレッジ測定ツール。
  • AspectJ・・・アスペクト指向言語、ツール。
インストゥルメンテーションを使うと色々面白いことができるけど、リスクも多い。考慮点は以下の通り。
  1. 変更されたバイトコードそのものを見ることはできないから、ソースコードに書いた通りに動くことを求めているシチュエーションでは使うべきではない。つまり挙動そのものを書き換えないユースケースのみで使う方が安全。Lombokにはdelombokという機能で書き換えたソースコードを生成できる。NewRelicは性能監視しかしないので、副作用は限定的なはず。他のプロダクトは開発時やテスト時に使うのでほとんどの場合、実運用では使わない。AspectJは実運用でも使えてしまうので注意が必要。
  2. 複数のインストゥルメンテーション製品を使うとちゃんと動かないことがある。しかもエラーがわかりにくく、はまりやすい。
  3. リフレクションを使うよりは速い
  4. 学習コストが高い。バイトコードを操作する機能を作る時は、ASM、BCEL、Javassistなどを使うがどれも簡単ではない。例えばASMを使う場合はバイトコードとJVMの動作の仕組みを理解する必要がある。

DockerでMQ環境を作る

DockerHubの ibmcom/mq を使う。ファイルシステムとしてtmpfsは使えないので これ を参考に/mnt/sda1に置き換える。 brew install docker docker-machine docker-machine create --drive...