|
2008年03月01日
JavaScript 仕様
Rhino
は元々 Mozilla プロジェクトで開発されていた Pure Java 製の JavaScript (ECMAScript)
エンジンです。JDK 1.1 からの長い歴史を持ち (そして一時期の暗黒時代を経て)、
Java SE 6 の Scripting API 実装として標準バンドルされています。
Java SE 6 の Rhino 1.6 は以下の仕様に準拠しています。
ECMA 仕様では構文や組み込み関数などを定義しているのみであり、一般的なブラウザ
で使用できる document や alert() などの実行環境に依存する機能は
用意されていません。しかし同等の暗黙オブジェクトを Java 側で追加することが
可能です。
Rhino お試し実行
Java SE 6 以降がインストールされている環境であれば以下のアプレットでスクリプト
の試行が可能です。実際どの程度のことが出来るのか試してみたい場合に使用して
下さい。使い方はこちら。
構文と機能
Rhino 1.6 でサポートされている機能は以下の通りです (実地で調べた結果なので他
にもあるかもしれません)。
| 構文/機能 |
|
1.6 |
| 定数リテラル |
null, true, false, undefined, NaN, Infinity |
○ |
| ビルトイン関数 |
eval(), parseInt(), parseFloat(), escape(), unescape(), isNaN(), isFinite(), print(), println() |
○ |
| ビルトイン型 |
Array, Boolean, Number, String, Date, Math, Function, Object, RegExp, void |
○ |
| コメント |
/* */, // |
○ |
| 演算子 |
+, -, *, /, %, ++, --, <<, <<<, >>, =, +=, -=, *=, /=, %=, &=, |=, ^=, ==, !=, <=, >=, <, >, !, &&, ||, &, |, ^, ~, 条件? A: B, new, delete, typeof |
○ |
| if 構文 |
if(条件){ … } else if(条件){ … } else { … } |
○ |
| switch 構文 |
switch(値){ // 値は文字列も可 case 値1: … break; … default: … break; } |
○ |
| for 構文 |
for(初期化; 条件; 加減算){ … } for(変数 in 集合){ … } for each(変数 in 集合){ … } |
○ |
| while 構文 |
while(条件){ … } do{ … } while(条件); |
○ |
| try 構文 |
try{ … throw 値; //呼び出し先の関数でも可 } catch(変数){ … } finally { … } |
○ |
| 変数定義 |
var x = 100; |
○ |
| 関数定義 |
function foo(引数1,引数2,…){ … return 値; } |
○ |
| プロトタイプ |
function Foo(){…} Foo.prototype.bar = function(){…} var x = new Foo(); x.bar(); |
○ |
| 正規表現 |
"abcdefg".search(/ABC/i) |
○ |
| ECMA3 |
class, public, protected, private, final, abstract, static, synchronized, native |
△
(予約のみ) |
| XML |
var x = <foo><bar>100</bar></foo>; |
- |
Java のクラスを使用する
スクリプト内での Java クラスの使用は至って簡単です。単純に FQN で指定するだけ
でインスタンスの構築からメソッド呼び出し、フィールドアクセスまであらゆる操作が
可能です。
Rhino
// print("hello, world") と等価
java.lang.System.out.println("hello, world");
// ダイアログを表示
javax.swing.JOptionPane.showMessageDialog(null,"hello, world");
// 初期化したボタンを結果として返す
var button = new javax.swing.JButton();
button.setLabel("ボタン");
button;
プリミティブ型の配列を構築する時だけは少々コツが必要で、
Array
クラスにプリミティブ Wrapper クラスの TYPE を指定します。
Rhino
var buffer = java.lang.reflect.Array.newInstance(
java.lang.Byte.TYPE, 1024);
FQN での指定はコードが冗長になりがちですが JavaImporter() を使用する
ことで import 宣言と同様にパッケージ名を省略することが出来ます (ただし
with の使用はあまり効率が良くないと Rhino 公式サイトで言及されています)。
Rhino
var ns = JavaImporter(java.awt, javax.swing);
with(ns){
var button = new JButton();
button.setFont(new Font("Dialog", Font.PLAIN, 12));
button.setLabel("ボタン");
button;
}
Rhino から Java で可能な機能が全て利用できる事に注意してください。サンドボックス
の外で動作している場合、スクリプトから以下の処理が行えてしまいます。
- ファイルの読み込み、書き込み、一覧取得、削除
- 任意のサーバとの通信
- 任意のクラスをロード、実行
スタンドアロンアプリケーションや JEE コンテナなどで信頼できない (誰が作ったか
分からない) スクリプトを動作させることは致命的な脆弱性につながりますので注意
してください。
暗黙オブジェクトの追加
スクリプト実行前に
ScriptContext
の
Bindings
にオブジェクトを指定することでスクリプトの暗黙オブジェクトを追加することが出来
ます。
Java
ScriptContext context = engine.getContext();
Bindings bind = context.getBindings(ScriptContext.ENGINE_SCOPE);
bind.put("foo", new Object(){
public String getBar(){
return "bar";
}
});
ENGINE_SCOPE
は同一 ScriptEngine インスタンス上で共有されるバイン
ディングをを表します。この他に同一 ScriptEngineFactory インスタンスで共有
される
GLOBAL_SCOPE
を使用することが出来ます。
スクリプトからはバインドしたオブジェクトの public フィールドやメソッドにアクセス
することが出来ます。特にオブジェクトが getter/setter を持つ場合、プロパティ名
でもアクセスすることが出来ます (上記の例では手を抜いて無名内部クラスで行っています)。
Rhino
// foo.bar でも良い
foo.getFoo();
また後述のビルトイン関数のように暗黙オブジェクトを定義するスクリプトを同一エンジン
上で実行しておくことでも目的を果たすことが出来ます。
これにより document や window などに相当するオブジェクトをゴリ
ゴリ作成してブラウザ並みに仕立て上げることも可能になっています。
ビルトイン関数の追加
オブジェクトを指定しなくても使用できるトップレベルのビルトイン関数は、あらか
じめ同一のエンジン上でその関数の定義を評価しておく事で使用することができます。
例えば alert() (本来は window のメソッドですが…) を定義するには
以下のように関数定義スクリプトを同一エンジン上で実行しておきます。
Java
engine.eval(
"function alert(msg){" +
"javax.swing.JOptionPane.showMessageDialog(null,msg);}"
);
engine.eval(yourScript);
プロパティ等
ScriptEngine#put() で設定できる値。
| 名前 |
説明 |
| javax.script.filename |
スクリプトのファイル名。例外メッセージなどに使用される。 |
|
|