InfoQ

Articles

JRuby アプリケーションを Java Web Start でデプロイする

作者 Mirko Stocker, 翻訳者 岡田 英久 投稿日 2008年4月8日 午後6時42分

コミュニティ
Java,
Ruby
トピック
コンパイラ,
JRuby,
動的言語,
デプロイ/データセンター
タグ
JRuby,
デプロイ

Ruby と Java がひとつになった世界に足を踏み入れるにはひとつの命令が必要だ。


include Java

この命令を実行することで、あなたは Java のクラスをインスタンス化し、それらのもつメソッドを呼び出し、またそれらのクラスを拡張することすらできるようになる。あたかもそれらがごく普通の Ruby のオブジェクトであるかのように。だが、そこにはいくつかの微妙な違いがある。この記事では、それらのクラスをどのように扱えば、新しいアプリケーションをすばやく生み出し、イナズマのようなスピードでそれをユーザに提供できるのかを見ていく。

この記事は JRuby と Swing を使ったシンプルな ObjectSpace ブラウザを実装するサンプルアプリケーションをベースに進めていく。ObjectSpace はシステム内のすべてのオブジェクトにアクセスする手段を提供してくれる Ruby のモジュールだ。たとえば、存在するすべての文字列を表示するには次のようにする。

ObjectSpace.each_object(String) do |string|
 puts string
end
私の irb セッションでこれを実行すると約 28,000 件の文字列が表示される。Swing と JRuby を使えば、さまざまなクラスとそのインスタンス、そして利用可能なメソッドをグラフィカルなインタフェースで表示することができる。さらに、パラメータをもたないメソッドを右端のパネル上でクリックして実行することも可能だ。

 

JRuby の ObjectSpace サポートはランタイムのパフォーマンスに悪影響を与えるため、デフォルトで無効になっている。これを有効にする方法については後ほど紹介する。まずは実装の興味深い詳細部分をいくつかを指摘し、JRuby の Java との統合を利用し始めるためのヒントを提供したい。

Java との統合

スクリプト中で Java をインクルードすれば、既存の Java クラスのサブクラス化を始めることができる。単純に Java クラスの完全限定名を指定すれば OK だ。サンプルアプリケーションではメインウインドウは JFrame を拡張する。また、次のように javax.swing と java.awt パッケージをクラスのスコープにインクルードすることもできる。こうすれば毎回クラスを利用するたびにフルネームを指定する必要がなくなる。

class MainWindow < javax.swing.JFrame
include_package 'javax.swing'
include_package 'java.awt' ...

あるいは、include_class ファンクションを使ってクラスを個別にインクルードしてもよい。この方法なら、利用しないクラスのための定数で名前空間が汚染されることもない。


super によるコンストラクタ呼出は通常の Ruby コードと同じように動作する。つまり、このクラスの initialize メソッドの先頭行で super("JRuby Object Browser") という呼出を行えば、フレームのタイトルを設定することができる。


javax.swing パッケージ全体をクラスにインクルードしていれば、Java クラスのインスタンス化は次のとおり簡単だ。

list_panel = JPanel.new
list_panel.layout = GridLayout.new(0, 3)

二行目をよく見ると、JPanel の layout フィールドに直接アクセスしているように思うかもしれないが、そうではない。JRuby が Java のオブジェクトにいくつかの便利なメソッドを追加しているのである。だから、上述のコードは次のように見慣れた書き方をすることもできる。

list_panel.setLayout(GridLayout.new(0, 3)) 

ゲッターとセッターを使う代わりに、一見したところフィールドへ直接アクセスしているようなコードを書ける。コーディングのエクスペリエンス全体がより Ruby ライクに感じられるように JRuby が Java オブジェクトに追加しているシンタックスシュガーは他にもあり、すべてのメソッド用に実際に定義されているキャメルケースの名前の代わりにスネークケースの名前を使うことができる。これに従えば setLayout メソッドを呼び出す三番目の方法は次のようになる。

list_panel.set_layout(GridLayout.new(0, 3)) 

セッターメソッドをそれが定義されているクラス内部で呼び出すときは、Ruby がそれをローカル変数の作成であると勘違いしないように、明示的に self をレシーバとしてメソッドを呼び出す必要がある。

self.default_close_operation = WindowConstants::EXIT_ON_CLOSE 

Java と Ruby の間にある別の違いは、前述のコード片にある EXIT_ON_CLOSE のような定数へのアクセスだ。コードを Java から Ruby に変換するときは . (ドット)によるアクセスを全部 :: に置き換えると覚えておこう。

ここまでは JRuby が Swing 開発にもたらした多くの変化はさほど革命的なものではないように見える。しかし私たちはまだ重要な側面をひとつ忘れている。イベントリスナだ。Java ではリスナとイベントを結びつける場合、無名クラスを使ってインタフェースを実装することが多い。

button.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent e) {
 ...
}
});

この方法だと、たくさんのリスナを追加する必要があるときにコードがごちゃごちゃしてしまう。JRuby を使えば、これを次のような二行のコードに切り詰めることができる( event 引数は必要がなければ省略することもできる)。

button.add_action_listener do |event|   
...
end

 以上が JRuby で Swing を使い始めるために知っておかなければならない基本事項である。JRuby が Swing を使った GUI 開発を快適にしてくれるとはいえ、やはり多くのコードを自分で書かなくてはならない。複雑なレイアウトを利用したいときは特にそうだ。Swing UI の生成をさらにシンプルにしたければ Three approaches to JRuby GUI APIs (参考記事・英語)を見てほしい。

JRuby アプリケーションのデプロイを簡単に

Ruby のアプリケーションやライブラリは通常 RubyGems を使って配布される。その恩恵を受けるにはあらかじめ Ruby と RubyGems がインストールされていなければならないが、平均的なエンドユーザの環境にはおそらくインストールされていない。この問題は、従来の( MRI / C-Ruby )プログラムを Ruby インタプリタといっしょにパッケージングしてくれる RubyScript2Exe [1] によってすでに解決済である。RubyScript2Exe は複数プラットフォームで動作する。だが JRuby ユーザが雨のなかに取り残されていると感じる必要はない。実際はまったく逆で、彼らはアプリケーションをすばやくデプロイするためのもっと強力なツールを手にしている。Java Web Start だ。

Java Web Start to the Rescue

Java Web Start は Java Runtime Environment に含まれているため、ほとんどのシステム上にインストールされている。Web Start 対応アプリケーションを作成するのは非常に簡単で、アプリケーションを構成する全ファイルがパッケージングされている Jar ファイルと JNLP( Java Network Launching Protocol )ディスクリプションファイルを作成するだけでよい。ObjectSpace ブラウザアプリケーションを実例として使い、Web Start 可能な Ruby アプリケーションを作成する過程を以下に示す。

Web Start に必須の要件は Jar ファイルにアプリケーションが含まれていることなので、まずはそこから見ていこう。JRuby は jruby-complete.jar と、機能を最小限に抑えた jruby.jar という二つの異なるライブラリを用意している。いずれも Ruby の標準ライブラリが全部バンドルされている。もし標準以外のライブラリを一切使わないのであれば、小さいほうの jruby.jar を使えばよい。そうすれば、大雑把に言って 1 MB ほどダウンロードサイズが削減できる。

自分で作成したスクリプトを実行するもっともシンプルな方法は .rb ファイルを jruby.jar に追加することだ。次のコマンドでは、今回のサンプルである rob.rb をアーカイブに追加している。

jar uf jruby.jar rob.rb  

これがちゃんと動くかどうかを確認するには、アプリケーションを java で実行すればよい。このアプリケーションには ObjectSpace モジュールが必要なので、Java に jruby.objectspace.enabled=true というプロパティを指定してこれを有効にしなければならない。

java -Djruby.objectspace.enabled=true -jar jruby.jar -r rob 

-r オプションでファイルを指定し、スクリプトを実行する。

事前コンパイル

JRuby 1.1 の新しいエキサイティングな機能のひとつは事前( Ahead of Time, AOT )コンパイルのサポートだ。現在の JRuby における JIT コンパイルではメソッド数が 2048 個までという制約(source)がある。AOT コンパイルはこの制約を和らげる助け(source)になる。JRuby のコンパイラである jrubyc はまだ開発途中なので、利用可能な最新の JRuby を使うのがよい。通常の Ruby ファイルをクラスファイルにコンパイルする方法は単純で、次に示すようにスクリプトを指定してコンパイラを実行するだけでよい。

jrubyc rob.rb 

これで rob.class ファイルを含む ruby ディレクトリが作成される。 上でやったように ruby ディレクトリを jruby.jar に追加するかわりに、アプリケーションを格納する別の Jar ファイルを作成してみよう。やはり、既存の Jar ファイルに変更を加えるというのはきれいな解決方法ではない。Jar ファイルは jar という同名のツールを使って作成できる。

jar -cfe rob.jar ruby/rob.class ruby 
これで rob.jar という小さなサイズの Jar ファイルが作成される。ruby/rob.class は main-class として Manifest ファイルで指定され、Jar に追加される。これで、実行にはクラスを指定するだけで他にはコマンドラインで何も指定する必要がなくなり、起動が単純になる。これを実行するには rob.jar がクラスパスに含まれている必要がある。
java -Djruby.objectspace.enabled=true -cp rob.jar:jruby.jar ruby.rob 

Web Start

続けて JNLP ファイルを記述する前に、先ほど作成した Jar ファイルに署名をしなくてはならない。JRuby はリフレクションを使っておりパーミッションの拡大を必要とするので、この手続きは残念ながら不可欠だ。JRuby Wiki により詳しい情報が載っている。もっとも簡単な方法は次のように JDK 付属の keytool を使って自分でテスト用の証明書を作成することだ。

keytool -genkey -keystore myKeystore -alias myself
keytool -selfcert -alias myself -keystore myKeystore

これ以降、 Jar ファイルのうちのひとつを変更するたびに署名を更新しなければ、実行時に SecurityException がスローされる。

jarsigner -keystore myKeystore jruby.jar myself
jarsigner -keystore myKeystore rob.jar myself

 Jar ファイルの準備ができたので、今度こそ JNLP ファイルを見ていこう。以下に示しているのがアプリケーションのための最小限の設定だ。 title、 vendor、 j2se といったタグや security セクションなど、一部のフィールドは仕様によって必須とされている。jar タグは Jar ファイルが最終的に置かれる場所を指している。file://- という URL を使えばローカルファイルを指定することもできる。これは開発中に便利だ。ObjectSpace プロパティはここでも設定する必要があり、これは property タグを使って行う。





Mirko Stocker











 ひとつ上で説明した事前コンパイル( AOT )の項をスキップした場合や、Jar ファイルをひとつしか用いない方法を使いたい場合は、JNLP ファイルに -r オプションが含まれるように変更しなければならないので、application-desc は次のようになる。最後のステップは Jar と JNLP ファイルの指定した場所へのアップロードだ。それが終われば、ブラウザを使ってリンクを開くか、シェルから直接 javaws ツールを使えばアプリケーションを実行できる。

[...]

-r
rob

[...]

最後のステップは Jar と JNLP ファイルの指定した場所へのアップロードだ。それが終われば、ブラウザを使ってリンクを開くか、シェルから直接 javaws ツールを使えばアプリケーションを実行できる。

 

トラブルシューティング 

ブラウザが Web Start を使ってアプリケーションを起動するためには、JNLP ファイルは application/x-java-jnlp-file という MIME タイプで配信されなければならない。もしブラウザが JNLP の内容を表示するだけで javaws を自動的に起動してくれないのであれば、Web サーバの設定を適切に行う必要がある。たとえば Apache なら mime.types 内に次のようなディレクティブが必要だ。

application/x-java-jnlp-file jnlp 

さらなる情報源

 JRuby に関する一般的な情報源としては JRuby Wiki が有用である。

  1. http://www.erikveen.dds.nl/rubyscript2exe/

Ruby Object Browser のコードはこちらから(source)ダウンロードできる。

原文はこちらです:http://www.infoq.com/articles/jruby-deployment-with-webstart

ブックマーク
digg+,
reddit+,
del.icio.us+,
dzone+,
Hatena

No comments

返信

ジャンル別一覧

Coplien氏とMartin氏、TDDとCDDそしてプロフェッショナルの定義について大いに語る。

このビデオは、BobとJim Coplien氏がこれに関連する話や、いくつかの他の話題について議論する様子を納めたものだ。TDDと契約による設計(Design by Contract)の比較や、システムとビジネスドメインモデルを調和させるためには、事前にどれくらいのアーキテクチャ設計をしておかなければならないのか、などが議論されている。(翻訳:近藤 修平 - (株)永和システムマネジメント)

.NET Webサービス向けのサービスレジストリの実装

本稿では、SOAソリューションの実装を単純化するために利用できるサービスレジストリの.NET実装を説明します。

John Lamが語るIronRubyの現状

InfoQは、独創的なRubyCLRの開発者であり、IronRubyを世に出すためにマイクロソフトが雇い入れたJohn Lam氏と話す機会を得た。Johnの正式な肩書きはDynamic Language Runtimeチームのプログラムマネジャーである。

人に愛されるリモートミーティングの手引き

テレカンファレンスとデスクトップを共有するツールを使いこなすことは、現在のビジネスにおいて重要なスキルになっています。本稿は、これらの情報と裏技を提供します。

NetKernelで実装したRESTfulなESB

Jeremy Deane takes a look at writing a Restful ESB. He explains how commercial ESB's were considered and NetKernel was ultimately used to provide the implementation.

Lean開発者のスタート: チームのスタートアップ時間の削減

アジャイルプラクティスは新チームメーンバーが知りたい情報を直接提供するものではありません。そこで私は、新しいチームメンバーの「セットアップ時間」の削減するために、新しいプラクティスを提案します。

複数のアジャイルチームでのバージョン管理

このレポートでは複数のチームが動いているアジャイル環境において、どのようにバージョン管理を行えばいいかを説明します。このスキームは"Scrum and XP from the Trenches(InfoQのミニブック)に出てきた企業で私たちが新しく採用した方法です。

ErlangとYawsを使ったRESTfulサービス

本稿では、Steve Vinoski氏が、プログラミング言語ErlangとWebサーバーYawsを使用したRESTful Webサービスを構築する方法を説明します。