本腰入れてJRuby(その3) Apache BSFさんと仲良くなろう

BSFのドキュメントがほとんどなくて困ってうろうろしたので、分かった事を書いていく。
BSFを使ったスクリプトの呼び出しはこんな感じ。

BSFManager manager = new BSFManager();
String hello = "Javaの世界からこんにちは!";
manager.registerBean("hello", hello); // (1)
InputStreamReader reader = new InputStreamReader(this.getClass().getResource("test.rb").openStream());
manager.exec("ruby", "(java)", -1, -1, IOUtils.getStringFromReader(reader));

test.rbは、この処理を実装しているクラスと同じパッケージに置いている事を前提にしています。(ってあたりまえかw)
test.rbの中身はこんな感じ。

hello = $bsf.lookupBean("hello")
puts hello

$bsfというのは、BSFManagerをラップしたBSFFunctionsというクラスの暗黙オブジェクト。BSFManager#registerBeanで登録したBeanをlookupBeanで取得することができます。

BSFManagerにはもう一つ、BSFManager#declareBean(String beanName,Object bean,Class beanClass)というインターフェースがあり、こちらを使うと宣言したbeanはさっきの$bsfからlookupBeanしなくてもそのまま使えます。どういうことかと言うと、

String hello = "Javaの世界からこんにちは!";
// manager.registerBean("hello", hello); // (1)
manager.declareBean("hello", hello,String.class); // (1)をこう置き換える
puts $hello

と言うように呼べます。が、BSFManagerのソースを見てみると、すべてのScriptEngineに対してdeclareBeanで宣言したBeanが登録されていました。局所的に使うBeanを登録するにはちょっとスコープが広すぎるわけです。(Rubyの世界だと'$'がついている変数はグローバルスコープなんすね。Rhinoだと"bsf"のまんまで呼び出せた。他の言語だとどうなんだろう。)

BSFの対応言語はJRuby以外にもJavaScript(Rhino)やJython、Groovyとかがあり、実行時にどの言語かを指定することができます。(Scalaがなくてビックリした)

String source;
// JRuby
manager.exec("ruby", "(java)", -1, -1,source);
// Rhino
manager.exec("javascript", "(java)", -1, -1,source);
// Jython
manager.exec("jython", "(java)", -1, -1,source);
// Groovy
manager.exec("groovy", "(java)", -1, -1,source);

BSFManagerと同じパッケージにあるLanguage.propertiesでScriptEngineとマッピングしているようです。またファイルの拡張子からどの言語か判断して実行するインターフェースもあります。

String langType = BSFManager.getLangFromFilename(filename);

Java6でサポートされたJSR233のインターフェースの方が実行速度的に優位ですが、Java5でも動く環境にするのならBSFを使わないといけません。JRubyのインターフェースを直で叩く事も考えられますが、JRubyの開発者は推奨していません。(そりゃそうだ。)