目次


動的言語を動的に呼び出す

第 1 回 Java スクリプト API 入門

実行中のアプリケーションを javax.script API を使って変更する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: 動的言語を動的に呼び出す

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:動的言語を動的に呼び出す

このシリーズの続きに乞うご期待。

Java 開発者は、Java 言語が必ずしもすべての作業に最適ではないことを知っています。今年リリースされた JRuby と Groovy の 1.0 バージョンによって、Java アプリケーションに動的言語を追加することへの関心が高まりました。Groovy や JRuby、Rhino、Jython などのオープン・ソース・プロジェクトによって、いわゆるスクリプト言語でコードを作成することができ、そしてそれを JVM の中で実行することができます (「参考文献」を参照)。しかしこれらの言語を Java コードと統合するということは、通常は各インタープリター固有の API と機能を学ぶ必要がある、ということを意味していました。

Java SE 6 に追加された javax.script パッケージによって、動的言語の統合が容易になりました。このパッケージを利用すると、ごくわずかのインターフェースや具象クラスのセットを使って、1 つの単純な方法で非常にさまざまな種類のスクリプト言語を呼び出すことができます。しかし Java スクリプト API は、アプリケーションの一部をスクリプト化しやすくするだけではありません。つまりスクリプト・パッケージによって、実行時に外部スクリプトを読み取り、そして呼び出すことができます。これは、これらのスクリプトを動的に変更できること、それによって実行中のアプリケーションの振る舞いを変更できることを意味します。

この記事は 2 回シリーズの第 1 回として、Hello World スタイルのアプリケーションを使いながら Java スクリプト API の機能と重要なクラスを紹介します。第 2 回では、このスクリプト API の実力をさらに顕著に示す現実的なサンプル・アプリケーションについて解説します。第 2 回のアプリケーションでは、スクリプト API を使って動的なルール・エンジンを作成します。このルール・エンジンでのルールは Groovy と JavaScript、そして Ruby で作成された外部スクリプトとしてエンコードされています。これらのルールによって、住宅ローンの申込者に対して、その人が特定の不動産担保ローン商品に適格かどうかを判断します。Java スクリプト API を使ってルールを外部化することで、ルールの変更や新しい不動産担保ローン商品の追加を実行時に行えるようになります。

Java スクリプト API

スクリプト・パッケージは、Java アプリケーションにスクリプト言語を統合するための統一的な方法を提供するために、2006年12月に Java 言語に追加されました。このパッケージによって、言語開発者は、自分たちが作成した言語を Java アプリケーションから動的に呼び出すために必要なグルー・コードを作成することができます。Java 開発者の立場から見ると、このスクリプト・パッケージはいくつかのクラスとインターフェースを提供しており、それらを利用すると、さまざまな言語で作成されたスクリプトを共通の API を使って呼び出すことができます。従ってこのスクリプト・パッケージは、さまざまな言語 (さまざまなデータベースなど) を一貫したインターフェースを使って Java プラットフォームに統合できるという意味で、JDBC (Java Database Connectivity) パッケージと似ています。

これまでは、Java コードから動的にスクリプト言語を呼び出そうとすると、各言語のディストリビューションで提供される固有のクラスを使うか、あるいは Apache の Jakarta BSF (Bean Scripting Framework) を使う必要がありました。BSF では、1 つの API の背後にいくつかのスクリプト言語が統合されています (「参考文献」を参照)。大部分を BSF をベースにしている Java SE 6 スクリプト API を利用すると、AppleScript や Groovy、JavaScript、Jelly、PHP、Python、Ruby、そして Velocity など 20 数種類を超えるスクリプト言語を Java コードに統合することができます。

このスクリプト API によって、Java アプリケーションと外部スクリプトが、お互いに相手を見られるようになります。Java コードが外部スクリプトを呼び出せるだけではなく、外部スクリプトからも、選択された Java オブジェクトにアクセスできるようになります。例えば、外部の Ruby スクリプトが Java オブジェクトのメソッドを呼び出し、それらのプロパティーにアクセスすることができます。つまりこれらのスクリプトによって、開発時には想定されていなかった振る舞いを実行中のアプリケーションに追加することができます。

外部スクリプトを呼び出す機能は、実行時におけるアプリケーションの機能強化や、構成、監視、その他のランタイム操作 (アプリケーションを停止させずにビジネス・ルールを変更するなど) に使用することができます。スクリプト・パッケージの使い方としては、次のようなものが考えられます。

  • 本格的なルール・エンジンを使わずに、Java 言語よりも単純な言語でビジネス・ルールを作成する。
  • ユーザーがアプリケーションを即座にカスタマイズできるプラグイン・アーキテクチャーを作成する。
  • 既存のスクリプト (例えばテキスト・ファイルを処理する、あるいは変換するスクリプトなど) を Java アプリケーションに統合する。
  • アプリケーションの実行時の振る舞いを、プロパティー・ファイルではなく本格的なプログラミング言語を使って外部で構成する。
  • Java アプリケーションにドメイン固有言語を追加する。
  • Java アプリケーションのプロトタイピングの際にスクリプト言語を使う。
  • アプリケーションのテスト・コードをスクリプト言語で作成する。

Hello World をスクリプト言語で作成する

HelloScriptingWorld クラス (この記事の他のコードと共にダウンロードすることができます (「参考文献」を参照)) は、この Java スクリプト・パッケージの重要な機能を表しています。このクラスは、ハードコーディングされた JavaScript のスニペットをスクリプト言語の例として使っています。このクラスの main() メソッド (リスト 1) は JavaScript スクリプト・エンジンを作成し、そしてこのスクリプト・パッケージの機能を際立たせている 5 つのメソッドを呼び出します (これらのメソッドのリストは後ほど示します)。

HelloScriptingWorld の main メソッド
public static void main(String[] args) throws ScriptException, NoSuchMethodException {

ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("JavaScript");

    if (jsEngine == null) {
        System.err.println("No script engine found for JavaScript");
        System.exit(1);
    }

    System.out.println("Calling invokeHelloScript...");
    invokeHelloScript(jsEngine);

    System.out.println("\nCalling defineScriptFunction...");
    defineScriptFunction(jsEngine);

    System.out.println("\nCalling invokeScriptFunctionFromEngine...");
    invokeScriptFunctionFromEngine(jsEngine);

    System.out.println("\nCalling invokeScriptFunctionFromJava...");
    invokeScriptFunctionFromJava(jsEngine);

    System.out.println("\nCalling invokeJavaFromScriptFunction...");
    invokeJavaFromScriptFunction(jsEngine);
}

main() メソッドの主な機能は、javax.script.ScriptEngine のインスタンスを取得することです (リスト 1の最初の 2 つのステートメント) 。スクリプト・エンジンは、ある特定の言語のスクリプトをロードして実行します。スクリプト・エンジンは、Java スクリプト・パッケージの中で最も頻繁に使われ、そして最も重要なクラスです。スクリプト・エンジンは、javax.script.ScriptEngineManager (最初のステートメント) から取得することができます。典型的なプログラムでは、多くのスクリプト言語が使われている場合を除き、スクリプト・エンジンの 1 つのインスタンスを取得すればよいだけです。

ScriptEngineManager クラス

ScriptEngineManager は、スクリプト・パッケージの中で頻繁に使われる、おそらく唯一の具象クラスです。それ以外に使用されるものの大部分はインターフェースです。またスクリプト・パッケージの中で、直接インスタンス化される (あるいは Spring Framework などの依存性注入機構によって間接的にインスタンス化される) 唯一のクラスかもしれません。ScriptEngineManager がスクリプト・エンジンを返す方法は、次の 3 つのうちのいずれかです。

  • エンジン名、あるいは言語名によって (例えばリスト 1 では JavaScript エンジンを要求しています)。
  • その言語でスクリプト用に一般的に使われているファイル拡張子によって (例えば Ruby スクリプトの場合は .rb、など)。
  • スクリプト・エンジンが処理方法を知っているものとして宣言した MIME タイプによって。

ScriptEngineManagers はスクリプト・エンジンを間接的に発見し、また作成します。つまり、スクリプト・エンジン・マネージャーがインスタンス化されていると、これらのマネージャーは Java 6 で追加されたサービス発見の機構を使って、クラスパスに登録されたすべての javax.script.ScriptEngineFactory 実装を発見します。これらのファクトリー・クラスには Java スクリプト API の実装がパッケージされているため、これらのファクトリー・クラスを直接扱う必要はありません。

ScriptEngineManager はスクリプト・エンジンのファクトリー・クラスをすべて発見すると、それぞれを照会し、それが要求された型のスクリプト・エンジン (リスト 1 の場合は JavaScript エンジン) を作成できるかどうかを判断します。あるファクトリーが、要求された言語用のスクリプト・エンジンを作成できると答えると、スクリプト・エンジン・マネージャーはそのファクトリーにスクリプト・エンジンを作成するように依頼し、そしてそのファクトリーは作成したスクリプト・エンジンを呼び出し側に返します。もし要求された言語用のファクトリーが発見できない場合には、マネージャーは null を返します。リスト 1のコードは、これに備えて null の戻り値をチェックしています。

ScriptEngine インターフェース

先ほど触れたように、このコードは ScriptEngine のインスタンスを使ってスクリプトを実行します。スクリプト・エンジンは、スクリプト・コードと、(最終的にコードを実行する) ベースとなる言語インタープリターまたはコンパイラーとの間のメディエーターとして動作します。そのため、各インタープリターがどのクラスを使ってコードを実行するのかを知る必要がありません。例えば、JRuby 用のスクリプト・エンジンは、最初に JRuby の org.jruby.Ruby クラスのインスタンスにコードを渡してスクリプトを中間形式にコンパイルし、そしてその中間形式を再度呼び出してスクリプトを評価し、戻り値を処理することができます。スクリプト・エンジンの実装によって、インタープリターがクラス定義やアプリケーションのオブジェクト、入出力ストリームなどを Java コードと共有する方法の詳細が隠されるのです。

図 1 は、アプリケーションと Java スクリプト API、ScriptEngine の実装、そしてスクリプト言語のインタープリターとの間の一般的な関係を示しています。これを見ると、アプリケーションが、ScriptEngineManager クラスと ScriptEngine インターフェースを提供するスクリプト API のみに依存していることがわかります。ScriptEngine の実装コンポーネントは、特定のスクリプト言語用のインタープリターを使うための詳細を処理します。

図 1: スクリプト API のコンポーネントの関係
Evolutionary Path to Full Automation
Evolutionary Path to Full Automation

スクリプト・エンジンの実装と言語のインタープリターに必要な JAR ファイルをどこで取得するのか、と思う人がいるかもしれません。スクリプト・エンジンの実装を探すための最初の場所としては、java.net がホストするオープン・ソースの Scripting プロジェクト (「参考文献」を参照) が最適です。このプロジェクトでは、多くの言語のためのスクリプト・エンジンの実装と、他の場所でホストされているスクリプト・エンジンの実装へのリンクを見つけることができます。また Scripting プロジェクトは、このプロジェクトがサポートするスクリプト言語用のインタープリターをダウンロードするためのリンクも提供しています。

リスト 1 では、main() メソッドは、各メソッドの JavaScript コードを評価するために使用する ScriptEngine を各メソッドに渡します。この最初のメソッドをリスト 2 に示します。invokeHelloScript() メソッドはスクリプト・エンジンの eval メソッドを呼び出し、指定された JavaScript コードのストリングを評価して実行します。ScriptEngine インターフェースは、オーバーロードされた 6 つの eval() メソッドを定義します。これらのメソッドは、ストリング、あるいは java.io.Reader オブジェクトとして評価されるスクリプトを受け付けます (java.io.Reader はファイルなどの外部ソースからスクリプトを読み取るために一般的に使われます)。

invokeHelloScript メソッド
private static void invokeHelloScript(ScriptEngine jsEngine) throws ScriptException {
    jsEngine.eval("println('Hello from JavaScript')");
}

invokeHelloScript() メソッドの JavaScript は、Hello from JavaScript を標準出力ストリーム (この場合はコンソール・ウィンドウ) に出力します。(リスト 6 には HelloScriptingWorldApplication を実行したことによる完全な出力が含まれています。)

このクラスの、このメソッドや他のメソッドが、javax.script.ScriptException をスローすることを宣言していることに注目してください。この (スクリプト・パッケージで定義されている唯一の) チェック例外は、エンジンが、指定されたコードの構文解析あるいは実行に失敗したことを示します。スクリプト・エンジンのすべての eval() メソッドは ScriptException をスローすることを宣言しているため、これをコードで適切に処理できる必要があります。

リスト 3 は、これに関連する 2 つのメソッド、defineScriptFunction()invokeScriptFunctionFromEngine() を示しています。defineScriptFunction() メソッドも、ハードコーディングされた JavaScript のスニペットを使ってスクリプト・エンジンの eval() メソッドを呼び出します。ただし、このメソッドは JavaScript の関数 sayHello() を定義すること以外は何もしないことに注意してください。コードは実行されていません。sayHello() 関数は 1 つのパラメーターをとり、これを次の println() 文でコンソールに出力します。スクリプト・エンジンの JavaScript インタープリターは、この関数をインタープリターのグローバル環境に追加し、その後 eval() メソッドを呼び出してこの関数を利用できるようにします (このメソッドの呼び出しは、(ご想像通り) invokeScriptFunctionFromEngine() メソッドの中で実行されています)。

defineScriptFunction メソッドと invokeScriptFunctionFromEngine メソッド
private static void defineScriptFunction(ScriptEngine engine) throws ScriptException {
    // Define a function in the script engine
    engine.eval(
        "function sayHello(name) {" +
        "    println('Hello, ' + name)" +
        "}"
    );
}

private static void invokeScriptFunctionFromEngine(ScriptEngine engine)
  throws ScriptException
{
    engine.eval("sayHello('World!')");
}

この一対のメソッドは、スクリプト・エンジンがアプリケーション・コンポーネントの状態を維持すること、そしてその状態を、後でエンジンの eval() メソッドを呼び出す際に利用できることを示しています。invokeScriptFunctionFromEngine() メソッドは、この維持された状態を利用し、前に eval() を呼び出す際に定義されたJavaScript 関数 sayHello() を呼び出します。

多くのスクリプト・エンジンは、eval() を呼び出してから次に呼び出すまでの間、グローバル変数と関数の状態を維持します。しかし重要な注意点として、Java スクリプト API はスクリプト・エンジンがこの機能を提供することを要求しません。しかしこの記事で使用している JavaScript と Groovy、そして JRuby のスクリプト・エンジンは、eval() を呼び出してから次に呼び出すまでの間、状態を維持します。

リスト 4 は前の例のバリエーションを示しています。この invokeScriptFunctionFromJava() メソッドは、ScriptEngine の eval() メソッドあるいは JavaScript コードを使わずに JavaScript 関数 sayHello() を呼び出すという点が異なります。このメソッドは代わりに、Java スクリプト API の javax.script.Invocable インターフェースを使って、スクリプト・エンジンが維持管理する関数を呼び出します。invokeScriptFunctionFromJava() メソッドはスクリプト・エンジンのオブジェクトを Invocable インターフェースにキャストし、そしてそのインターフェースの invokeFunction() メソッドを呼び出し、特定のパラメーターを使って JavaScript 関数 sayHello() を呼び出します。呼び出された関数が値を返すと、invokeFunction() メソッドは、その値を Java Object 型としてラップして返します。

invokeScriptFunctionFromJava メソッド
private static void invokeScriptFunctionFromJava(ScriptEngine engine)
  throws ScriptException, NoSuchMethodException
{
Invocable invocableEngine = (Invocable) engine;
    invocableEngine.invokeFunction("sayHello", "from Java");
}

リスト 4 には JavaScript が含まれていないことに注意してください。Invocable インターフェースを使うことによって、Java コードはスクリプトの実装言語を知らなくてもスクリプトの関数を呼び出すことができます。invokeFunction() メソッドは、指定された名前またはパラメーター型を持つ関数をスクリプト・エンジンが見つけられないと、java.lang.NoSuchMethodException をスローします。

Java スクリプト API はスクリプト・エンジンが Invocable インターフェースを実装することを要求しません。しかし現実的には、リスト 4のコードは、スクリプト・エンジンが Invocable インターフェースを実装していることを、キャストを行う前に instanceof 演算子を使って確認する必要があります。

スクリプト・コードから Java メソッドを呼び出す

リスト 3リスト 4 の例は、スクリプト言語で定義された関数またはメソッドを Java コードが呼び出す方法を示しています。皆さんはおそらく、スクリプト言語で作成されたコードを使って Java オブジェクトのメソッドを呼び出せるのか疑問に思っているかもしれませんが、呼び出せるのです。リスト 5 の invokeJavaFromScriptFunction() メソッドは、スクリプト・エンジンが Java オブジェクトを利用できるようにする方法と、その Java オブジェクトのメソッドをスクリプト・コードで呼び出す方法を示しています。正確に言えば、invokeJavaFromScriptFunction() メソッドは、スクリプト・エンジンの put() メソッドを使って HelloScriptingWorld クラスのインスタンス自体をエンジンに提供します。put() メソッドを呼び出す際に提供される名前を使ってエンジンが Java オブジェクトにアクセスできると、そのオブジェクトは eval() メソッドへの呼び出しの中のスクリプト・コードで使われます。

invokeJavaFromScriptFunction メソッドと getHelloReply メソッド
private static void invokeJavaFromScriptFunction(ScriptEngine engine)
  throws ScriptException
{
    engine.put("helloScriptingWorld", new HelloScriptingWorld());
    engine.eval(
        "println('Invoking getHelloReply method from JavaScript...');" +
        "var msg = helloScriptingWorld.getHelloReply(vJavaScript');" +
        "println('Java returned: ' + msg)"
    );
}

/** Method invoked from the above script to return a string. */
public String getHelloReply(String name) {
    return "Java method getHelloReply says, 'Hello, " + name + "'";
}

リスト 5 の中で、eval() メソッドへの呼び出しに含まれる JavaScript コードは、Java オブジェクト HelloScriptingWorld を使います。このオブジェクトへのアクセスは、スクリプト・エンジンの put() メソッドを呼び出す際に指定される変数名 helloScriptingWorld を使って行われます。JavaScript コードの 2 行目は、(同じくリスト 5 に示す) Java のパブリック・メソッド getHelloReply() を呼び出します。getHelloReply() メソッドは、ストリング Java method getHelloReply says, 'Hello, <parameter>' を返します。eval() メソッドの JavaScript コードは msg 変数に Java の戻り値を割り当て、そしてその値をコンソールに出力します。

ScriptEngine.put と、これに関連する get() メソッドは、スクリプト・エンジン内で実行する Java コードとスクリプトの間でオブジェクトとデータを共有するための基本的な方法です。(この話題の詳細については、この記事の後の方で説明する「スクリプト実行のスコープ」を参照してください。) スクリプト・エンジンの put() メソッドを呼び出すと、エンジンは指定されたストリング・キーと 2 番目のパラメーター (任意の Java オブジェクト) とを関連付けます。大部分のスクリプト・エンジンは、指定された変数名でこれらの Java オブジェクトをスクリプトが利用できるようにします。スクリプト・エンジンは、put() メソッドに渡す名前を自由に変更することができます。例えば JRuby スクリプト・エンジンは、グローバル変数用の Ruby の構文に合うように、helloScriptingWorld$helloScriptingWorld というグローバル変数として Ruby コードで利用できるようにします。

スクリプト・エンジンの get() メソッドは、スクリプト環境の中で得られる値を取得します。一般的には、スクリプト環境の中にあるすべてのグローバル変数とグローバル関数は、Java コードから get() メソッドを使ってアクセスすることができます。しかしスクリプトが利用できるのは、put() を使って明示的にスクリプト・エンジンと共有される Java オブジェクトのみです。

実行中のアプリケーションの Java オブジェクトに外部スクリプトがアクセスでき、操作できるという、この機能は、Java プログラムの機能を拡張するための強力な方法です。(第 2 回の例では、この方法の詳細を解説します。)

HelloScriptingWorld アプリケーションを実行する

HelloScriptingWorld アプリケーションを実行するためには、ソース・コードをダウンロードしてビルドします。.zip ファイルには、サンプル・アプリケーションをコンパイルして実行するための Ant スクリプトと Maven ビルド・ファイルの両方が含まれています。下記のステップで作業を行います。

  1. .zip ファイルをダウンロードします。
  2. 新しいディレクトリー (例えば java-scripting など) を作成し、ステップ 1 でダウンロードしたファイルを、このディレクトリーに解凍します。
  3. コマドライン・シェルを開き、このディレクトリーに変更します。
  4. ant run-hello を実行します。

リスト 6 に示すような、Ant のコンソール出力が表示されるはずです。defineScriptFunction() メソッドが何も出力を生成していないことに注目してください。これは、このメソッドは JavaScript 関数を定義しても呼び出しはしないためです。

HelloScriptingWorld を実行したことによる出力
Calling invokeHelloScript...
Hello from JavaScript

Calling defineScriptFunction...

Calling invokeScriptFunctionFromEngine...
Hello, World!

Calling invokeScriptFunctionFromJava...
Hello, from Java

Calling invokeJavaFromScriptFunction...
Invoking getHelloReply method from JavaScript...
Java returned: Java method getHelloReply says, 'Hello, JavaScript'

Java 5 との互換性

Java SE 6 では Java スクリプト API が導入されましたが、この API を Java SE 5 で実行することもできます。そのためには、単に Java SE 5 に欠けている javax.script パッケージ・クラスの実装を提供すればよいだけです。幸い、Java Specification Request 223 のリファレンス実装の中に、利用できる 1 つの実装があります (「参考文献」のダウンロードへのリンクを参照してください)。JSR 223 は Java スクリプト API を定義しています。

JSR 223 リファレンス実装をダウンロードしたら、このファイルを解凍し、script-api.jar ファイルと script-js.jar ファイル、そして js.jar ファイルをクラスパスに配置します。これらのファイルは、Java SE 6 にバンドルされているスクリプト API と JavaScript スクリプト・エンジン・インターフェース、そして JavaScript スクリプト・エンジンを提供します。

スクリプト実行のスコープ

スクリプト・エンジンの中で実行中のスクリプトに Java オブジェクトを公開するための方法は、単にスクリプト・エンジンの get() メソッドと put() メソッドを呼び出す以外にも構成方法があります。スクリプト・エンジンの get() メソッドあるいは put() メソッドを呼び出すと、エンジンは要求された鍵を javax.script.Bindings インターフェースのデフォルトのインスタンスの中で取得するか、あるいはこのインスタンスの中に保存します。(Bindings インターフェースは、鍵を強制的にストリングにする単なる Map インターフェースです。)

スクリプト・エンジンの eval() メソッドをコードから呼び出すと、スクリプト・エンジンにデフォルトで設定されている鍵と値のバインディングが使われます。しかし eval() メソッドを呼び出す際に独自の Bindings オブジェクトを提供すれば、その特定のスクリプトからどの変数とオブジェクトが見えるかを制限することができます。この呼び出しは、eval(String, Bindings) あるいは eval(Reader, Bindings) のようになります。スクリプト・エンジンは、カスタマイズした Bindings を作りやすいように、空の Bindings オブジェクトを返す createBindings() メソッドを提供しています。Bindings オブジェクトを使って eval() メソッドを呼び出すことで、その前にスクリプト・エンジンのデフォルト・バインディングに保存された Java オブジェクトを一時的に隠すことができます。

さらに補足しておくと、スクリプト・エンジンには 2 つのデフォルト・バインディングが含まれています。それは、get()put() を呼び出す際に使われる「エンジン・スコープ」バインディングと、「エンジン・スコープ」バインディングの中にオブジェクトが見つからない場合にスクリプト・エンジンがオブジェクトを参照するために使用することができる「グローバル・スコープ」バインディングです。『できる』という言葉に重要な意味があります。つまりスクリプト・エンジンは、必ずしもグローバル・バインディングをスクリプトから利用できるようにする必要はないのです。しかし大部分のスクリプト・エンジンは利用できるようにしています。

「グローバル・スコープ」バインディングが設計されている背景には、オブジェクトをさまざまなスクリプト・エンジンで共有するという目的があります。ScriptEngineManager インスタンスが返すすべてのスクリプト・エンジンは、同じ「グローバル・スコープ」バインディング・オブジェクトを共有しています。あるエンジンのグローバル・バインディングは getBindings(ScriptContext.GLOBAL_SCOPE) メソッドを使って取得することができ、また setBindings(Bindings, ScriptContext.GLOBAL_SCOPE) を使って設定することができます。

ScriptContext は、スクリプト・エンジンのランタイム・コンテキストを定義し、そしてコントロールするインターフェースです。スクリプト・エンジンの ScriptContext に含まれるものには、「エンジン」スコープと「グローバル」スコープのバインディング、そしてエンジンが標準の入出力操作に使用する入出力ストリームがあります。スクリプト・エンジンのコンテキストを取得し、操作するには、そのエンジンの getContext() メソッドを使います。

スコープやバインディング、コンテキストなど、スクリプト API の概念は、それぞれが重複する意味を持っているために、最初はわかりにくいかもしれません。この記事のソース・コードのダウンロード・ファイルには、ScriptApiRhinoTest と呼ばれる JUnit テスト・ファイルが src/test/java ディレクトリーに含まれており、これらの概念を Java コードを通して理解するために役立つはずです。

次回は

Java スクリプト API の基本事項は理解できたので、第 2 回では、この知識をもっと現実的なサンプル・アプリケーションを使って改善し、拡張します。このアプリケーションは、Groovy と Ruby、そして JavaScript を組み合わせて作成された外部スクリプト・ファイルを使って、実行時に変更できるビジネス・ロジックを定義します。第 2 回を読めばわかるように、スクリプト言語でビジネス・ルールを定義することでルールを記述しやすくなり、プログラマーではない人 (ビジネス・アナリストやルール作成者など) にとって、おそらくルールが読みやすくなります。


ダウンロード可能なリソース


関連トピック

  • 動的言語を動的に呼び出す、第 2 回,」: このシリーズの後半では、Ruby や Groovy、JavaScript で記述された外部スクリプトを実行する方法と、アプリケーションを停止して再始動することなく、外部スクリプトを変更してビジネス・ロジックを変更する方法を説明します。
  • この Java 仕様リクエストJSR-223: Scripting for the Java Platform は、Java SE 6 に追加された Java スクリプト API を定義しています。
  • Sun による JDK 6 のドキュメンテーション、Java Scripting Programmer's Guide には Java スクリプト API に関するプログラマーズ・ガイドが含まれています。
  • Jakarta の BSF (Bean Scripting Framework) プロジェクトは Java スクリプト API の基礎となっています。
  • 「Making Scripting Languages JSR-223-Aware」(Thomas Künneth 著、java.net、2006年9月) は、既存のスクリプト・エンジンがない場合にスクリプト言語を Java スクリプト API で利用できるようにする方法を説明した記事です。
  • developerWorks のシリーズ記事、「実用的な Groovy」で Groovy について深く学んでください。
  • Mozilla Rhino には、Sun Microsystems と BEA Systems から入手できる Javaランタイムに同梱の JavaScript エンジンについて学ぶためのドキュメンテーションその他のリソースが用意されています。
  • JRuby は純粋に Java で実装した Ruby プログラミング言語です。このプロジェクトの Web サイトには、プロジェクトの最新ニュースや JRuby を使うためのリソースが用意されています。
  • Java SE 6 と BEA JRockit は Java スクリプト API をネイティブでサポートする開発キットとランタイム環境であり、この中には簡易版の Mozilla Rhino JavaScript エンジンが含まれています。
  • java.net でのオープン・ソースの Scripting プロジェクトは、約 20 数種類の言語のためのスクリプト・エンジン・インターフェースと、他の既知の Java スクリプト・エンジンへのリンクを提供しています。これらのスクリプト言語の 1 つを使用するためには、スクリプト・エンジンの実装の JAR ファイルを (そのスクリプト言語のインタープリター自体の JAR ファイルと共に) このプロジェクトからインストールします。
  • JSR-223 の基準実装 Scripting for the Java Platform 1.0 Reference Implementation は、Java スクリプト API を Java SE 5 で実行するための 3 つの JAR ファイルを提供しています。これらを利用するためには sjp-1_0-fr-ri.zip ファイルをダウンロードして解凍し、そして js.jar ファイルと script-api.jar ファイル、そして script-js.jar ファイルをクラスパスに置きます。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=259479
ArticleTitle=動的言語を動的に呼び出す: 第 1 回 Java スクリプト API 入門
publish-date=09042007