|
|
|
Norris Boyd |
|
Rhino Architect |
|
|
|
|
The JavaScript programming language implemented
using Java technology |
|
|
|
No browser objects |
|
|
|
Intended for embedding in applications |
|
|
|
|
Runs within other programs |
|
Automates objects of its host environment |
|
|
|
|
|
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 |
|
|
|
|
Web content in Java clients without native code |
|
User-level scripting of applications |
|
Server-side scripting |
|
Scripting for exploratory programming and
testing |
|
|
|
|
Use as a “macro” language |
|
|
|
Satisfy power users with little extra work by
adding scripting |
|
|
|
Example: Netscape Process Manager |
|
|
|
|
|
|
Exploratory programming |
|
|
|
Testing |
|
|
|
|
Use the Rhino shell |
|
|
|
Embed Rhino in your application |
|
|
|
|
Simple read-eval-print loop |
|
Defines extra convenience functions |
|
|
|
js> 3+4 |
|
7 |
|
js> function f(a) { |
|
print(a); |
|
} |
|
js> f(7) |
|
7 |
|
|
|
|
|
|
|
|
|
|
|
$ java RunScript 'Math.cos(Math.PI)' |
|
-1 |
|
$ java RunScript 'function f(x){return x+1}
f(7)' |
|
8 |
|
|
|
|
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(); |
|
} |
|
} |
|
|
|
|
Context cx = Context.enter(); |
|
|
|
Creates and enters a Context |
|
A Context stores information about the execution
environment of a script |
|
|
|
|
|
|
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 |
|
|
|
|
|
|
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 |
|
|
|
|
|
|
System.out.println(cx.toString(result)); |
|
|
|
result could be a string, JavaScript object,
etc. |
|
The toString method converts any JavaScript
value to a string |
|
|
|
|
Context.exit(); |
|
|
|
Exiting the context removes the association |
|
between the context and the current thread |
|
|
|
|
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(); |
|
} |
|
} |
|
|
|
|
|
|
|
No additional code in the embedding needed! |
|
|
|
$ java RunScript
'java.lang.System.out.println(3)' |
|
3.0 |
|
undefined |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
Custom host objects can implement special
JavaScript features like dynamic properties |
|
|
|
Try out new host object classes in the shell |
|
|
|
|
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 |
|
|
|
|
|
|
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; |
|
} |
|
|
|
|
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; } |
|
|
|
|
|
|
|
|
The
class name is defined by the getClassName method: |
|
|
|
public String getClassName() { return
”Counter"; } |
|
|
|
|
|
|
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++; } |
|
|
|
|
|
|
Methods can be defined using the jsFunction_ prefix. Here we define resetCount
for JavaScript. |
|
|
|
public void jsFunction_resetCount() { count = 0;
} |
|
|
|
|
The
method ScriptableObject.defineClass uses a Java class to define a
JavaScript “class” in a particular scope: |
|
|
|
ScriptableObject.defineClass(scope,Counter.class); |
|
|
|
|
|
|
Using Rhino, JavaScript objects can implement
arbitrary Java interfaces |
|
No Java code to write–it’s part of Rhino’s
LiveConnect |
|
|
|
|
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 |
|
|
|
|
|
|
|
|
Interpreter mode |
|
|
|
Compiled mode |
|
|
|
|
|
Interpreter mode is slow compared to the browser’s interpreter
written in C... |
|
|
|
|
|
|
…but
compiled mode makes use of the JIT to beat the browser’s interpreter. |
|
|
|
|