5 「Nashorn JavaScriptエンジンの概要」
Nashorn JavaScriptエンジンを使用すると、データベースでJavaScriptを直接実行できます。既存のクライアント側JavaScriptをデータベースで再利用でき、それをJava SEライブラリと組み合せると、RDBMSセッションで直接実行できる、機能が豊富で強力な汎用性の高いデータバインドされたアプリケーションの設計が可能になります。ここでは、次の各項でNashorn JavaScriptエンジンについて説明します。
5.1 Nashorn JavaScriptエンジンの使用について
Oracle Database 12cリリース2 (12.2.0.1)以降では、Oracle JVMに組み込まれているNashorn JavaScriptを使用して、データベース内でJavaScriptを実行できます。データベースでJavaScriptを直接実行すると、次の利点があります。
- 既存のスキルおよびコードの再利用
- Oracle Databaseにあるデータの送信の回避。データベースでJavaScriptを実行すると、データベース内部でのJSONドキュメントのより速いインプレース処理が可能になります。これにより、外部インフラストラクチャへのデータの送信が回避でき、ネットワーク・オーバーヘッドが回避されるため、パフォーマンスを向上させることができます。
- 新しいデータべース機能の実現
Oracle JVMのNashorn エンジンを使用して、セッションでJavaScriptコードを実行するには、スキーマにDBJAVASCRIPTロールを付与する必要があります。このロールには、データベースでNashornを実行するのに必要なパーミッションが含まれます。ロールはDBAが付与でき、ユーザーごとに1回のみ付与する必要があります。
JavaScriptソースをOracle Databaseで管理するには、それらをJavaリソースとしてスキーマにロードしてからデータベース内でスクリプトを実行するのが望ましい方法です。
注意:
- Nashornクラスの直接起動は、Oracle JVMでは制限されています。
- Oracle JVMでは、すべてのスクリプティング・モードの拡張機能が無効になっています。
- スクリプトは文字列またはファイル・ストリームのいずれかから標準スクリプティングAPIを使用して実行できますが、これはお薦めしません。この方法で起動されたスクリプトは、デフォルトのパーミッションでサンドボックス・モードでのみ実行できます。
5.1.1 スキーマへのJavaScriptコードのロード
loadjavaコマンドを使用してJavaScriptコードをデータベース・スキーマにロードします。スクリプトはJavaリソースとしてロードされます。たとえば、次のようなJavaScriptファイルhello.jsがあるとします。
function hello()
{
/*
*This is a sample Javascript file that prints "Hello World".
*/
var hellow = "Hello World";
return hellow;
}
var output = hello();
print(output);
次のコマンドを使用して、hello.jsスクリプト・ファイルをyourschemaというスキーマにロードします。
loadjava -v -u yourschema hello.jsloadjavaコマンドにより、パスワードの入力が要求された後、次の出力とともにスキーマ・ローカル・リソースhello.jsが作成されます。
arguments: '-u' 'yourschema/***' '-v' 'hello.js'
creating : resource hello.js
loading : resource hello.js
Classes Loaded: 0
Resources Loaded: 1
Sources Loaded: 0
Published Interfaces: 0
Classes generated: 0
Classes skipped: 0
Synonyms Created: 0
Errors: 0また、次のコマンドを使用して、hello.jsファイルがデータベースに正常にロードされたるかどうかを確認することもできます。
select object_name, object_type from user_objects;その後、このリソースは次の各項で説明する方法を使用してNashornエンジンに渡すことができます。
5.1.2 Oracle JVMにおけるJavaScriptの実行方法
データベースにロードしたスクリプトは、次の3つの方法で実行できます。
5.1.2.1 DBMS_JAVASCRIPT.RUN PL/SQLプロシージャの使用
この方法は、値を戻さないJavaScriptプロシージャに便利です。引数としてリソース名を指定するためにDBMS_JAVASCRIPT.RUNプロシージャを起動します。スキーマにDBJAVASCRIPTロールが付与されていることを確認します。DBMS_JAVASCRIPT.RUNプロシージャは、oracle.aurora.rdbms.DbmsJavaScript.run Javaメソッドのラッパーで、Nashorn機能を内部的に起動します。
SQLからの場合
call dbms_javascript.run('hello.js');JavaScriptコードが出力値を戻す場合は、次の命令を使用して標準出力デバイスに値を表示する必要があります。
SQL>set serveroutput on
SQL>call dbms_java.set_output(20000);
SQL>call dbms_javascript.run("hello.js");
PL/SQLからの場合
dbms_javascript.run('hello.js');JavaScriptコードが出力値を戻す場合は、次の命令を使用して標準出力デバイスに値を表示する必要があります。
SQL>set serveroutput on
SQL>call dbms_java.set_output(20000);
SQL>call dbms_javascript.run("hello.js");
5.1.2.2 DbmsJavaScript Javaクラスの使用
これは、スキーマのパーミッションをJavaScriptコードに適用できるようになるため、Oracle JVMでJavaコードからスクリプトを起動するのに好ましい方法です。データベースで実行されるJavaコードからリソースhello.jsとしてロードされるJavaScriptを起動します。次のコード・スニペットに示すように、リソース名を引数として渡してoracle.aurora.rdbms.DbmsJavaScriptクラスのメソッド実行を起動します。
注意:
スキーマにDBJAVASCRIPTロールが付与されていることを確認します。
import oracle.aurora.rdbms.DbmsJavaScript;
…
DbmsJavaScript.run("hello.js");5.1.2.3 標準javax.script Javaパッケージの使用
この方法は、値を戻すJavaScript関数に便利です。通常、次のタスクを実行します。
注意:
スキーマにDBJAVASCRIPTロールが付与されていることを確認する必要があります。
-
loadjavaコマンドを使用して、JavaScriptをJavaリソースとしてデータベースにロードします。 -
javax.scriptパッケージを使用してJavaScriptを実行します。 -
スクリプト・マネージャをインスタンス化します
-
エンジンを作成します
-
エンジンの
evalメソッドに対する引数としてリソース・ストリーム・リーダーを渡します。
次のコード・スニペットでは、javax.scriptパッケージを使用してリソースhello.jsからコードを実行する方法を示します。
import javax.script.*;
import java.net.*;
import java.io.*;
...
// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine =
factory.getEngineByName("javascript");
// create schema resource URL
URL url = Thread.currentThread()
.getContextClassLoader().getResource("hello.js");
engine.eval(new InputStreamReader(url.openStream()));
...
文字列からJavaScriptコードを読み取ることもできます。次のコード・スニペットでは、文字列からJavaScriptコードを読み取って評価する方法を示します。
// evaluate JavaScript code from String
engine.eval(new StringReader(<script>));そうではなく、ファイルからJavaScriptコードを読み取ることもできます。ただし、これには追加の権限が必要となります。次のコード・スニペットでは、script_nameファイルからJavaScriptコードを読み取って評価する方法を示します。
import javax.script.*;
...
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("JavaScript");
engine.eval(new FileReader("script_name"));JacaScriptコードの評価後、通常、JavaScript関数を起動するために次のタスクを実行します。
-
Nashornエンジンを
InvocableにキャストしてinvokeFunctionを使用します。たとえば、
hello.jsスクリプトでhelloというJavaScript関数を定義すると、次のコード・スニペットに示すように、これらのタスクを実行できます。// create a JavaScript engine as above Invocable invocable = (Invocable) engine; Object myResult = invocable.invokeFunction("hello"); ...注意:
invocable.invokeFunctionを使用するかわりに、スクリプトの内部から起動されるJavaメソッドに戻り値を渡す方法があります。この代替方法は、必要となるボイラープレート・コードが少なくなるため好ましく、DBMSJAVASCRIPT.RUNプロシージャと互換性があります。たとえば、JavaScriptリソース
hello.jsでselectQuery関数を定義し、次のようにクラスQueryTestで定義したprint()Javaメソッドに結果を渡すとします。public static void print (String results) { System.out.println("my results: \n" + results); }その場合、JavaScriptからこれを実現するには、次の行を
hello.jsファイルに追加します。var queryTest = Java.type("QueryTest"); queryTest.print(selectQuery("all"));ここで、次の方法のいずれかで
hellp.jsを起動します。DbmsJavaScript.run("hello.js"); DBMS_JAVASCRIPT.RUN('hello.js'); -
次の例に示すように、JavaScriptアプリケーションを起動するためにPL/SQLプロシージャを作成します。
-- Create a procedure for select CREATE OR REPLACE PROCEDURE selectproc(id IN varchar2) IS output varchar2(10000); BEGIN SELECT invokeScriptEval(id) INTO output from dual; htp.prn(output); END; / SHOW ERRORS;
