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
Q & A

Performance Detail