JAX-WSを使ったVirtualBoxウェブサービスクライアントライブラリ

JavaOneでの収穫の一つは、VirtualBoxの最新版(1.6.0)にウェブサービスAPIがついているということ。Javaから VirtualBoxをいじったり、別のマシン上のVirtualBoxを操作するのにはこれが一番の方法です。僕のday jobの一つはMetroウェブサービスツールキットなので、その観点からも興味があったし、またHudsonのスレーブを仮想マシンにしたら面白そうだと前々から思っていたので、このAPIでまずは遊んでみることにしました。


さて、実際に VirtualBoxWSDLwscompileコンパイラにかけてみたのですが、でてきたコードが使いづらい。というのも、VirtualBoxオブジェクト指向SOAP上でエミュレートする独自の方式を編み出していて、当然のことながらツールがこの仕組みを理解できるはずも無いからです。WS-Addressingとかを使っていてくれればまだやりようもあるのですが、この独自方式というのは、「thisポインタ」を文字列であらわしてそれをやりとりするという、いわゆるCのライブラリデザインの方式に相当するやり方です。そして、Cよりも悪いことに、全ての仮想thisポインタはjava.lang.Stringなので、戻り値やパラメータの値がどの型のポインタを渡す・受け取るのかわからない。


次のコードを見るとこの独自方式がどういう風になっているかわかります。このやり方だと、IDEのオートコンプリーションに頼ってコードを書くというのがとても難しくなります。

// in the COM API
IMachine machine;
result = machine->getName();

// in web service API
String machine;
result = port.iMachineGetName(machine);

これを発見していらい、どうやってこの問題を解決するか数日考えていたのですが、偶然にも、VirtualBoxAPIの真のソースは XMLファイルに書かれていることを発見しました。ということで、これを読み込んで、ちょっとしたGroovyスクリプトを書いて、このウェブサービスAPIをラップするライブラリを自動生成することにしました。これによって、もっと自然でオブジェクト指向APIを作ることが出来ました。


できたライブラリはjarファイルにパッケージしたので、他のプロジェクトから使ってやって下さい。このライブラリを使ったコードは次のような感じになります。

IVirtualBox box = VirtualBox.connect("http://129.145.132.188:18083/");
System.out.println("version="+box.getVersion());

for(IMachine machine : box.getMachines()) {
    System.out.println(machine.getName());
}

ライブラリはJAX-WSに依存しているので、JavaSE6を使うか、JAX-WS 2.0の実装を依存ライブラリに加えて下さい。テストはMetro 1.1.1でやりました。


ライブラリ自体はMavenでビルドされていて、コード生成をするスクリプトを呼ぶためにGMaven を使っています。コード生成自体は拙作のCodeModelを使います。 GMavenを使うことで、コード生成部分をわざわざ別なMavenプラグインとして作らなくても済んでいます。GMavenには欠点も幾つか見つけましたが、全体としては割と気に入ったので、今後のプロジェクトでも使おうと思います。CodeModelをGroovy向けに拡張するのも余裕があればやってみたいところです。


最後に、ライブラリはJAX-WS commonsの一部として公開してあります。