Embedding Rhino
|
|
|
Norris Boyd |
|
Rhino Architect |
What is Rhino?
|
|
|
The JavaScript programming language
implemented using Java technology |
|
|
|
No browser objects |
|
|
|
Intended for embedding in applications |
Embedding Rhino
|
|
|
Runs within other programs |
|
Automates objects of its host
environment |
Rhino Features
|
|
|
|
ECMA-262 compliant |
|
Additional features of the latest
JavaScript language version (1.4) |
|
regular expressions |
|
function closures |
|
Java-style exceptions |
|
Optional class file generation gives
good performance |
|
LiveConnect |
What can I do with Rhino?
|
|
|
Web content in Java clients without
native code |
|
User-level scripting of applications |
|
Server-side scripting |
|
Scripting for exploratory programming
and testing |
User-level Scripting
|
|
|
Use as a “macro” language |
|
|
|
Satisfy power users with little extra
work by adding scripting |
|
|
|
Example: Netscape Process Manager |
Scripting to aid
development
|
|
|
|
|
Exploratory programming |
|
|
|
Testing |
How do I use Rhino?
|
|
|
Use the Rhino shell |
|
|
|
Embed Rhino in your application |
Rhino shell
|
|
|
Simple read-eval-print loop |
|
Defines extra convenience functions |
|
|
|
js> 3+4 |
|
7 |
|
js> function f(a) { |
|
print(a); |
|
} |
|
js> f(7) |
|
7 |
|
|
Embed Rhino
RunScript: A simple
embedding
|
|
|
|
|
|
|
$ java RunScript 'Math.cos(Math.PI)' |
|
-1 |
|
$ java RunScript 'function f(x){return
x+1} f(7)' |
|
8 |
RunScript.java
|
|
|
import org.mozilla.javascript.*; |
|
public class RunScript { |
|
public static void main(String args[]) |
|
throws JavaScriptException |
|
{ |
|
Context cx = Context.enter(); |
|
Scriptable scope = cx.initStandardObjects(null); |
|
Object result = cx.evaluateString(scope, args[0], |
|
"<cmd>", 1, null); |
|
System.out.println(cx.toString(result)); |
|
Context.exit(); |
|
} |
|
} |
Entering a Context
|
|
|
Context cx = Context.enter(); |
|
|
|
Creates and enters a Context |
|
A Context stores information about the
execution environment of a script |
|
|
Initializing standard
objects
|
|
|
Scriptable scope =
cx.initStandardObjects(null); |
|
|
|
Initializes the standard objects (Object,
Function, etc.) |
|
Must be done before scripts can be
executed |
|
Returns a scope object that we use in
later calls |
|
|
Evaluating a script
|
|
|
Object result =
cx.evaluateString(scope, args[0], |
|
"<cmd>", 1, null); |
|
|
|
Uses the Context cx to evaluate a
string |
|
Evaluation of the script looks up
variables in scope |
|
Errors will be reported with the
filename <cmd> and line number 1 |
|
|
Print the result
|
|
|
System.out.println(cx.toString(result)); |
|
|
|
result could be a string, JavaScript
object, etc. |
|
The toString method converts any
JavaScript value to a string |
Exit the Context
|
|
|
Context.exit(); |
|
|
|
Exiting the context removes the
association |
|
between the context and the current
thread |
Putting it together
|
|
|
import org.mozilla.javascript.*; |
|
public class RunScript { |
|
public static void main(String args[]) |
|
throws JavaScriptException |
|
{ |
|
Context cx = Context.enter(); |
|
Scriptable scope = cx.initStandardObjects(null); |
|
Object result = cx.evaluateString(scope, args[0], |
|
"<cmd>", 1, null); |
|
System.out.println(cx.toString(result)); |
|
Context.exit(); |
|
} |
|
} |
Expose Java APIs
Use Java APIs
|
|
|
|
|
No additional code in the embedding
needed! |
|
|
|
$ java RunScript
'java.lang.System.out.println(3)' |
|
3.0 |
|
undefined |
|
|
Add Java objects
|
|
|
|
|
Scriptable jsArgs =
Context.toObject(args, scope); |
|
scope.put("args", scope,
jsArgs); |
|
|
|
This adds a global variable args that is a JavaScript reflection of
the Java arguments to main |
|
|
|
$ java RunScript2
'java.lang.System.out.println(args[0])' |
|
java.lang.System.out.println(args[0]) |
|
undefined |
JavaScript host objects
Defining Host Objects
|
|
|
|
|
Custom host objects can implement
special JavaScript features like dynamic properties |
|
|
|
Try out new host object classes in the
shell |
Counter example
|
|
|
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.java
|
|
|
|
|
public class Counter extends
ScriptableObject { |
|
public Counter() { } |
|
public void jsConstructor(int a) { count = a; } |
|
public String getClassName() { return ”Counter"; } |
|
public int jsGet_count() { return count++; } |
|
public void jsFunction_resetCount() { count = 0; } |
|
private int count; |
|
} |
Counter’s constructors
|
|
|
The zero-argument constructor used by
Rhino runtime to create instances |
|
|
|
public Counter () { } |
|
|
|
Method jsConstructor defines the
JavaScript constructor |
|
|
|
public void jsConstructor(int a) {
count = a; } |
|
|
Class name
|
|
|
|
|
The class name is defined by the getClassName method: |
|
|
|
public String getClassName() { return
”Counter"; } |
Dynamic properties
|
|
|
|
|
Dynamic properties are defined by methods beginning with jsGet_ or jsSet_.
The method jsGet_count defines the count property. |
|
|
|
public int jsGet_count() { return
count++; } |
Defining JavaScript
“methods”
|
|
|
|
|
Methods can be defined using the jsFunction_ prefix. Here we define resetCount
for JavaScript. |
|
|
|
public void jsFunction_resetCount() {
count = 0; } |
Adding Counter to
RunScript
|
|
|
The method ScriptableObject.defineClass uses a Java class to define a
JavaScript “class” in a particular scope: |
|
|
|
ScriptableObject.defineClass(scope,Counter.class); |
Implementing interfaces
|
|
|
|
|
Using Rhino, JavaScript objects can
implement arbitrary Java interfaces |
|
No Java code to write–it’s part of
Rhino’s LiveConnect |
Implementing Runnable
|
|
|
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 |
How well does Rhino
perform?
|
|
|
|
|
|
|
Interpreter mode |
|
|
|
Compiled mode |
Rhino Structure
Interpreter mode
|
|
|
Interpreter mode is slow compared to the browser’s interpreter written
in C... |
|
|
Compiled mode
|
|
|
…but compiled mode makes use of the JIT to beat the browser’s
interpreter. |
Available on mozilla.org
Embedding Rhino
Performance Detail