手軽にRhinoのおいしい汁だけ吸ってみます。ディープに使うことは考えてないので注意。
Rhinoとは、Javaで書かれたJavaScript実行環境です。Javaと親和性が強く、JavaScriptからJavaを呼んだりJavaからJavaScriptを呼ばせたりすることが簡単にできます。最近ではJavaScriptと言えばAjaxですか、ここで紹介するRhinoの使い方はAjaxとは直接関係がなく*1、Javaで書くと固くなり過ぎる部分をJavaScriptで書いて柔軟性を生むと言うものです。Java SE 6では、Scripting for Java Platformが標準サポートされますので、Rhinoも標準機能としてJavaから使えることになります。ただし、ここで紹介する方法はScripting for Java Platformで規定されている方式ではなく、ラッピングされていないRhinoを直接呼ぶ方式で、Java SE 5 以前でも使えます。
では、まず、そもそもどうやってRhinoを使うかってところ。インストールは簡単で、ダウンロードサイトから最新版を落として展開し、js.jarをクラスパスに入れて下さい。以上。
次に基本的なコーディングです。JavaとJavaScriptを行ったり来たりするのであれば、様々なAPIを使う必要があるのですが、「Fileに入っているJavaScriptを実行して、実行された"結果"を保持したい」と言うことであれば、以下のような定石パターンでOKです。ここで言う"結果"にはコンパイル済の関数やオブジェクトも含みます。
File script = new File("my_script.js"); Context cx = Context.enter(); Object jsObject = null; try{ Scriptable global = cx.initStandardObjects(); FileReader r = new FileReader(script); jsObject = cx.evaluateReader(global, r, script.getAbsolutePath(), 1, null); r.close(); }finally{ Context.exit(); }
これでjsObjectにmy_script.jsの戻り値(最後に評価された値)が入ります。Object型でJavaScriptのオブジェクトが返って来たって、使い道がさっぱりわからないよ!! というツッコミもあるかと思いますが、その辺りは次のエントリで活用方法を紹介します。
で、簡単にこのコードを解説。まず、Contextですが、こいつはRhinoの実行情報を保持する働きがあるらしいです。スレッド毎に一つインスタンスが存在するらしいです。*3
ScriptableはJavaScriptのオブジェクトを表します。JavaScriptでは全てをObjectとそのプロパティとして表しますので、グローバルスコープもオブジェクトとして生成します。initStandardObjects()はグローバルスコープとして使えるオブジェクトを作るメソッドで、JavaScriptで利用する基本的なオブジェクト群を準備してこのオブジェクト経由で使えるようにしてくれます。
さて、この中で一番厄介なのがevaluateReader()。これはReaderからスクリプトを呼んで、コンパイル、実行をしてくれるのですが、引数が非常にわかりにくいです。
第一引数はスコープです。JavaScriptではスコープもオブジェクトとなり、このメソッドではスコープも呼び出し側がお世話してあげる必要があります。ここでは、グローバルスコープを渡しています。なお、JavaScriptのスコープの正体はスコープチェーンと呼ばれるオブジェクトの一連のリンクです。
第二引数はReaderです。これは特に問題無し。Rhinoの問題ではないのでここでは省略してますが、Encodeの扱いやBufferedReader等は随時調整してみて下さい。
弟三引数、第四引数はこのスクリプトのメタ情報で、ファイル名と開始行番号です。バグった時にこのファイル名と行番号でエラーが表示されます。これも呼び出し側が世話しなければなりません。
弟五引数はセキュリティ関連ですので省略。*4
とりあえずこれで、JavaScriptを実行する型紙はできました。次回以降は、Scriptに何を書くの? ってことやScriptからの戻り値をどう使うのかって辺りを書こうと思います。