現在位置: Rhino プロジェクト・ページ > Rhino 組み込み
チュートリアル: Rhino 組み込み
Rhino の組み込みは、簡単に、よい結果をもたらすことができます。 組み込み開発者側のさらなる努力によって、オブジェクトはスクリプトに公開され、 もっと便利にカスタマイズできます。
このチュートリアルでは、簡単な組み込みから、さらにカスタマイズされた複雑な組み込みまで、順を追って案内します。 十分 それに沿った、コンパイル可能なサンプルを提供します。
これらのサンプルは、配布物の rhino/examples ディレクトリ、
あるいは、cvs の mozilla/js/rhino/examples にもあります。
このドキュメントは、lxr を使用することで
リンクしています。
このドキュメントでは、緑で JavaScript コードを、緑で Java コードを、 そして 紫でシェルのログを示します。
本ドキュメントでは …
RunScript … 簡単な組み込み
Rhino でできる、もっとも簡単な組み込みは、RunScript サンプル のようなものです。 コマンドラインからスクリプトを読み込み、それを実行し、そして結果をプリントする、それだけです。
ここに、シェルコマンドラインからの、RunScript 使用例があります …
$ java RunScript "Math.cos(Math.PI)"
-1
$ java RunScript 'function f(x){return x+1} f(7)'
8
クラスパス (classpath) に、Rhino のクラスと RunScript サンプルのクラスファイルの 両方の指定が必要なことに注意してください。
さぁ、これから一行ずつ、main の中身を調べてみましょう。
コンテキストに入る (Entering a Context)
このコードは、Context を作成し、入ります。(enter します)
Context cx = Context.enter();
Context は、スクリプトの実行環境に関する情報を保持します。
標準オブジェクトの初期化
このコードは、標準のオブジェクトを初期化します (Object, Function, etc.)。
Scriptable scope = cx.initStandardObjects();
スクリプトを実行できるようにする前に、これを行っておく必要があります。
null パラメーターは、後の呼び出しに使用するスコープオブジェクト (scope) を、
作成して返すように、initStandardObjects に伝えます。
引数の取り集め
このコードは、標準の Java であり、Rhino 特有ではありません。 単にすべての引数を集めて、それらを一緒に連結するにすぎません。
String s = "";
for (int i=0; i < args.length; i++) {
s += args[i];
}
スクリプトを評価 (Evaluating)
このコードは、コンテキスト cx を使用し ストリングを評価 (evaluate) します。
Object result = cx.evaluateString(scope, s, "<cmd>", 1, null);
スクリプトの評価では、scope 内で変数を検索して、エラーについては、
ファイル名 <cmd> で行番号 1 としてレポートされるでしょう。
結果をプリント
このコードは、スクリプトの評価の結果 (変数 result の内容) をプリントします。
System.out.println(cx.toString(result));
result は、ストリング、JavaScript オブジェクト、または他の値かもしれません。
toString メソッドは、どんな JavaScript の値もストリングに変換します。
コンテキストを出る (Exit the Context)
このコードは、コンテキストを出ます。(exit します)
} finally {
Context.exit();
}
この、コンテキストと現スレッドとの関連付けの解除は、欠くことのできない後処理です。
enter 呼び出しのそれぞれに対して、exit 呼び出しがあるべきです。
例外 (exception) が投げられても、それが間違いなく呼び出されるように、Context.enter()
開始の後の、try ブロックに対応する finally ブロックに、それを記述します。
Java API のありさま
Java API の使用
組み込みに必要とされる追加コードはありません。 LiveConnect と呼ばれる JavaScript の機能で、JavaScript プログラムと Java オブジェクトが対話します (相互作用します) …
$ java RunScript 'java.lang.System.out.println(3)' 3.0 undefined
インターフェースの実装
Rhino を使用することで、JavaScript オブジェクトは、任意の Java インターフェースを実装することができます。 Java のコードを記述する必要はありません —— それは、Rhino の LiveConnect 実装の一部だからです。 例えば、java.lang.Runnable の実装の方法を、Rhino shell セッションで 見ることができます …
js> obj = { run: function() { print('hi'); } }
[object Object]
js> obj.run()
hi
js> r = new java.lang.Runnable(obj);
[object Object]
js> t = new java.lang.Thread(r)
Thread[Thread-0,5,main]
js> t.start()
hi
Java オブジェクトを追加
次の例は、RunScript2 です。 これは、RunScript とほとんど同じですが、2 行のコードの追加があります …
Object wrappedOut = Context.javaToJS(System.out, scope); ScriptableObject.putProperty(scope, "out", wrappedOut);
これらの行は、System.out の JavaScript 側への反映である、
グローバル変数 out を追加します …
$ java RunScript2 'out.println(42)' 42.0 undefined
Java から JavaScript オブジェクトを使用する
スクリプトを評価した後に、変数や関数のためにスコープを検索し、値を取り出したり、JavaScript 関数を呼び出したりすることが可能です。
これは、RunScript3 サンプルで説明されます。
このサンプルは、変数 x の値と、関数 f の呼び出しの結果を、プリントする機能が追加されます。
x と f の両方が、スクリプトの評価によって定義されると 期待できます。例えば、
$ java RunScript3 'x = 7'
x = 7
f is undefined or not a function.
$ java RunScript3 'function f(a) { return a; }'
x is not defined.
f('my args') = my arg
JavaScript 変数の使用
x の値をプリントするために、以下のコードを加えます。
Object x = scope.get("x", scope);
if (x == Scriptable.NOT_FOUND) {
System.out.println("x is not defined.");
} else {
System.out.println("x = " + Context.toString(x));
}
JavaScript 関数の呼び出し
関数 f を得て、それを呼び出し、そして結果をプリントするために、 このコードを加えます …
Object fObj = scope.get("f", scope);
if (!(fObj instanceof Function)) {
System.out.println("f is undefined or not a function.");
} else {
Object functionArgs[] = { "my arg" };
Function f = (Function)fObj;
Object result = f.call(cx, scope, scope, functionArgs);
String report = "f('my args') = " + Context.toString(result);
System.out.println(report);
}
JavaScript ホスト・オブジェクト
ホスト・オブジェクトの定義
カスタム・ホスト・オブジェクトは、動的プロパティーのような、特殊な JavaScript 機能を実装することができます。
Counter サンプル
Counter サンプルは、 簡単なホスト・オブジェクトです。下記の方法によって、その手順を経験できます。
シェルで組み込み関数 defineClass を使用して、新しいホスト・オブジェクトのクラスを試してみるのは簡単です。
後で、RunScript にそれを追加する方法を、見ることができます。
(java -jar オプションは、クラスパスを他に置き換えてしまうので、
それを使用して Counter クラスにアクセスすることはできないことに、注意してください)
$ java -cp 'js.jar;examples' org.mozilla.javascript.tools.shell.Main
js> defineClass("Counter")
js> c = new Counter(7)
[object Counter]
js> c.count
7
js> c.count
8
js> c.count
9
js> c.resetCount()
js> c.count
0
Counter のコンストラクター
引数のないコンストラクターは、Rhino ランタイムによって、インスタンスの作成に使用されます。 counter サンプルでは、初期化する必要がないので、実装は空になっています。
public Counter () { }
メソッド jsConstructor は、JavaScript コンストラクターを定義します。
それは、上記の JavaScript コード new Counter(7) の式で呼び出されます。
public void jsConstructor(int a) { count
= a; }
クラス名
クラス名は、getClassName メソッドによって定義されます。
これは、コンストラクター名を決定するのに使用されます。
public String getClassName() { return "Counter";
}
動的プロパティー
動的 (dynamic) プロパティーは、jsGet_ か jsSet_ で始まるメソッドで定義します。
メソッド jsGet_count は、count プロパティーを定義します。
public int jsGet_count() { return count++;
}
JavaScript コードの c.count 式 (あるいは表現)は、このメソッドを呼び出すことで、
上記の結果になります。
JavaScript の「メソッド」を定義
メソッドは、jsFunction_ 接頭語を使用して定義することができます。
ここに、JavaScript の resetCount を定義します。
public void jsFunction_resetCount() { count
= 0; }
上記の c.resetCount() は、このメソッドを呼び出します。
RunScript に Counter を追加
今度は、RunScript4 サンプルを見てください。これは、2 か所を除き RunScript と同じです。
メソッド ScriptableObject.defineClass に、Java のクラスを使用して、トップレベル・スコープで Counter "class" を定義します …
ScriptableObject.defineClass(scope, Counter.class);
すると、スクリプトから Counter オブジェクトを参照できるようになります …
$ java RunScript4 'c = new Counter(3); c.count; c.count;'
それから、Java のコードにより、Counter オブジェクトの新しいインスタンスを作り、
7 の値を使って構築し、それを、トップレベル変数 myCounter に割り当てます …
Object[] arg = { new Integer(7) };
Scriptable myCounter = cx.newObject(scope, "Counter", arg);
scope.put("myCounter", scope, myCounter);
すると、スクリプトから myCounter オブジェクトを参照できるようになります …
$ java RunScript3 'RunScript4 'myCounter.count; myCounter.count' 8