2001-04-25 00:31:31 +04:00
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
< html >
< head >
< meta http-equiv = "Content-Type" content = "text/html; charset=iso-8859-1" >
< meta name = "Generator" content = "Microsoft Word 97" >
< meta name = "GENERATOR" content = "Mozilla/4.75 [en] (WinNT; U) [Netscape]" >
< title > Embedding Rhino< / title >
< / head >
< body >
< center > < font size = +4 > Tutorial: Embedding Rhino< / font > < / center >
< p > Embedding Rhino can be done simply with good results. With more effort
on the part of the embedder, the objects exposed to scripts can be customized
further.
< p > This tutorial leads you through the steps from a simple embedding to
more customized, complex embeddings. Fully compilable examples are provided
along the way.
< p > The examples live in the < tt > rhino/examples< / tt > directory in the distribution
and in < tt > mozilla/js/rhino/examples< / tt > in cvs. This document will link
to them using < a href = "http://lxr.mozilla.org/" > lxr< / a > .
< p > In this document, JavaScript code will be in < font color = "#006600" > green< / font > ,
Java code will be in < font color = "#006600" > green< / font > , and shell logs
will be in < font color = "#663366" > purple< / font > .
< h3 >
< font size = +3 > Contents< / font > < / h3 >
< ul >
< li >
< font size = +1 > < a href = "#RunScript" > RunScript: A simple embedding< / a > < / font > < / li >
< ul >
< li >
< font size = +1 > < a href = "#EnteringContext" > Entering a Context< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#initializing" > Initializing standard objects< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Collecting" > Collecting the arguments< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Evaluating" > Evaluating a script< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Print" > Print the result< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Exit" > Exit the Context< / a > < / font > < / li >
< / ul >
< li >
< font size = +1 > < a href = "#Expose" > Expose Java APIs< / a > < / font > < / li >
< ul >
< li >
< font size = +1 > < a href = "#UseJava" > Use Java APIs< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#ImplementingInterfaces" > Implementing interfaces< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#AddJava" > Add Java objects< / a > < / font > < / li >
< / ul >
< li >
< font size = +1 > < a href = "#UsingJSObjs" > Using JavaScript objects from Java< / a > < / font > < / li >
< ul >
< li >
< font size = +1 > < a href = "#UsingJSvars" > Using JavaScript variables< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#CallingJSfuns" > Calling JavaScript functions< / a > < / font > < / li >
< / ul >
< li >
< font size = +1 > < a href = "#JavaScriptHostObjects" > JavaScript host objects< / a > < / font > < / li >
< ul >
< li >
< font size = +1 > < a href = "#DefiningHostObjects" > Defining Host Objects< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Counter" > Counter example< / a > < / font > < / li >
< ul >
< li >
< font size = +1 > < a href = "#CounterCtors" > Counter's constructors< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#classname" > Class name< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#Dynamic" > Dynamic properties< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#DefiningMethods" > Defining JavaScript "methods"< / a > < / font > < / li >
< li >
< font size = +1 > < a href = "#AddingCounter" > Adding Counter to RunScript< / a > < / font > < / li >
< / ul >
< / ul >
< / ul >
< hr WIDTH = "100%" >
< br > < a NAME = "RunScript" > < / a > < font size = +3 > RunScript: A simple embedding< / font >
< p > About the simplest embedding of Rhino possible is the < a href = "http://lxr.mozilla.org/mozilla/source/js/rhino/examples/RunScript.java" > RunScript
example< / a > . All it does it read a script from the command line, execute
it, and print a result.
< p > Here's an example use of RunScript from a shell command line:
< blockquote >
2003-02-03 04:17:44 +03:00
< pre > < font color = "#663366" > $ java RunScript "Math.cos(Math.PI)"
2001-04-25 00:31:31 +04:00
-1
$ java RunScript 'function f(x){return x+1} f(7)'
8< / font > < / pre >
< / blockquote >
Note that you'll have to have both the Rhino classes and the RunScript
example class file in the classpath. Let's step through the body of < tt > main< / tt >
one line at time.
< p > < a NAME = "EnteringContext" > < / a > < font size = +2 > Entering a Context< / font >
< p > The code
< blockquote >
< pre > < font color = "#006600" > Context cx = Context.enter();< / font > < / pre >
< / blockquote >
Creates and enters a < tt > Context. < / tt > A < tt > Context< / tt > stores information
about the execution environment of a script.
< br >
< p > < a NAME = "initializing" > < / a > < font size = +2 > Initializing standard objects< / font >
< p > The code
< blockquote >
2003-10-09 10:55:49 +04:00
< pre > < font color = "#006600" > Scriptable scope = cx.initStandardObjects();< / font > < / pre >
2001-04-25 00:31:31 +04:00
< / blockquote >
Initializes the standard objects (< tt > Object< / tt > ,
< tt > Function< / tt > , etc.)
This must be done before scripts can be executed. The < tt > null< / tt > parameter
tells < tt > initStandardObjects< / tt > to create and return a scope object
that we use in later calls.
< p > < a NAME = "Collecting" > < / a > < font size = +2 > Collecting the arguments< / font >
< p > This code is standard Java and not specific to Rhino. It just collects
all the arguments and concatenates them together.
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #006600" >
String s = "";
for (int i=0; i < args.length; i++) {
s += args[i];
}
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
< p > < br > < a NAME = "Evaluating" > < / a > < font size = +2 > Evaluating a script< / font >
< p > The code
< blockquote >
< pre > < font color = "#006600" > Object result = cx.evaluateString(scope, s, "< cmd>", 1, null);< / font > < / pre >
< / blockquote >
uses the Context < tt > cx< / tt > to evaluate a string. Evaluation of the script
looks up variables in < tt > scope< / tt > , and errors will be reported with
the filename < tt > < cmd>< / tt > and line number 1.
< br >
< p > < a NAME = "Print" > < / a > < font size = +2 > Print the result< / font >
< p > The code
< blockquote >
< pre > < font color = "#006600" > System.out.println(cx.toString(result));< / font > < / pre >
< / blockquote >
prints the result of evaluating the script (contained in the variable < tt > result< / tt > ).
< tt > result< / tt >
could be a string, JavaScript object, or other values..The
< tt > toString< / tt >
method converts any JavaScript value to a string.
< br >
< p > < a NAME = "Exit" > < / a > < font size = +2 > Exit the Context< / font >
< p > The code
< blockquote >
2002-07-09 21:49:16 +04:00
< pre style = "color: #006600" >
} finally {
Context.exit();
}
< / pre >
2001-04-25 00:31:31 +04:00
< / blockquote >
exits the Context. This removes the association between the Context and
the current thread and is an essential cleanup action. There should be
2002-07-09 21:49:16 +04:00
a call to < tt > exit< / tt > for every call to < tt > enter< / tt > . To make sure that it is called even if an exception is thrown, it is put into the finally block corresponding to the try block starting after < tt > Context.enter()< / tt > .
2001-04-25 00:31:31 +04:00
< br >
< dir > < / dir >
< a NAME = "Expose" > < / a > < font size = +3 > Expose Java APIs< / font >
< p > < a NAME = "UseJava" > < / a > < font size = +2 > Use Java APIs< / font >
< p > No additional code in the embedding needed! The JavaScript feature called
< i > LiveConnect< / i >
allows JavaScript programs to interact with Java objects:
< dir > < tt > < font color = "#663366" > $ java RunScript 'java.lang.System.out.println(3)'< / font > < / tt >
< br > < tt > < font color = "#663366" > 3.0< / font > < / tt >
< br > < tt > < font color = "#663366" > undefined< / font > < / tt > < / dir >
< a NAME = "ImplementingInterfaces" > < / a > < font size = +2 > Implementing interfaces< / font >
< p > Using Rhino, JavaScript objects can implement arbitrary Java interfaces.
There's no Java code to write--it's part of Rhino's LiveConnect implementation.
For example, we can see how to implement java.lang.Runnable in a Rhino
shell session:
< blockquote >
< pre > < font color = "#663366" > 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< / font > < / pre >
< / blockquote >
< a NAME = "AddJava" > < / a > < font size = +2 > Add Java objects< / font >
< p > The next example is < a href = "http://lxr.mozilla.org/mozilla/source/js/rhino/examples/RunScript2.java" > RunScript2< / a > .
This is the same as RunScript, but with the addition of two extra lines
of code:
2004-06-07 14:35:22 +04:00
< dir > < tt > < font color = "#006600" > Object wrappedOut = Context.javaToJS(System.out, scope);< / font > < / tt >
< br > < tt > < font color = "#006600" > ScriptableObject.putProperty(scope, "out", wrappedOut);< / font > < / tt > < / dir >
2001-04-25 00:31:31 +04:00
These lines add a global variable < tt > out< / tt > that is a JavaScript reflection
of the < tt > System.out< / tt > variable:
< dir > < tt > < font color = "#663366" > $ java RunScript2 'out.println(42)'< / font > < / tt >
< br > < tt > < font color = "#663366" > 42.0< / font > < / tt >
< br > < tt > < font color = "#663366" > undefined< / font > < / tt > < / dir >
< p > < br > < a NAME = "UsingJSObjs" > < / a > < font size = +3 > Using JavaScript objects
from Java< / font >
< p > After evaluating a script it's possible to query the scope for variables
and functions, extracting values and calling JavaScript functions. This
is illustrated in the < a href = "http://lxr.mozilla.org/mozilla/source/js/rhino/examples/RunScript3.java" > RunScript3< / a >
example. This example adds the ability to print the value of variable < tt > x< / tt >
and the result of calling function < tt > f< / tt > . Both < tt > x< / tt > and < tt > f< / tt >
are expected to be defined by the evaluated script. For example,
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #663366" >
$ java RunScript3 'x = 7'
x = 7
f is undefined or not a function.
$ java RunScript3 'function f(a) { return a; }'
x is not defined.
f('my args') = my arg
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
< a NAME = "UsingJSvars" > < / a > < font size = +2 > Using JavaScript variables< / font >
< p > To print out the value of < tt > x< / tt > , we add the following code.
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #006600" >
Object x = scope.get("x", scope);
if (x == Scriptable.NOT_FOUND) {
System.out.println("x is not defined.");
} else {
System.out.println("x = " + Context.toString(x));
}
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
< a NAME = "CallingJSfuns" > < / a > < font size = +2 > Calling JavaScript functions< / font >
< p > To get the function < tt > f< / tt > , call it, and print the result, we add
this code:
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #006600" >
Object fObj = scope.get("f", scope);
if (!(fObj instanceof Function)) {
System.out.println("f is undefined or not a function.");
} else {
Object functionArgs[] = { "my arg" };
Function f = (Function)fObj;
Object result = f.call(cx, scope, scope, functionArgs);
String report = "f('my args') = " + Context.toString(result);
System.out.println(report);
}
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
< p > < br > < a NAME = "JavaScriptHostObjects" > < / a > < font size = +3 > JavaScript host
objects< / font >
< p > < a NAME = "DefiningHostObjects" > < / a > < font size = +2 > Defining Host Objects< / font >
< p > Custom host objects can implement special JavaScript features like dynamic
properties.
< p > < a NAME = "Counter" > < / a > < font size = +2 > Counter example< / font >
< p > The < a href = "http://lxr.mozilla.org/mozilla/source/js/rhino/examples/Counter.java" > Counter
example< / a > is a simple host object. We'll go through it method by method
below.
< p > It's easy to try out new host object classes in the shell using its
built-in < tt > defineClass< / tt > function. We'll see how to add it to RunScript
later. (Note that because the < tt > java -jar< / tt > option preempts the rest
of the classpath, we can't use that and access the < tt > Counter< / tt > class.)
< blockquote >
2002-07-09 21:49:16 +04:00
< pre style = "color: #663366" >
$ java -cp 'js.jar;examples' org.mozilla.javascript.tools.shell.Main
2001-04-25 00:31:31 +04:00
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
2002-07-09 21:49:16 +04:00
0
< / pre >
2001-04-25 00:31:31 +04:00
< / blockquote >
< a NAME = "CounterCtors" > < / a > < font size = +2 > Counter's constructors< / font >
< p > The zero-argument constructor is used by Rhino runtime to create instances.
For the counter example, no initialization work is needed, so the implementation
is empty.
< dir > < tt > < font color = "#006600" > public Counter () { }< / font > < / tt > < / dir >
The method < tt > jsConstructor< / tt > defines the JavaScript constructor that
was called with the expression < tt > new Counter(7)< / tt > in the JavaScript
code above.
< dir > < tt > < font color = "#006600" > public void jsConstructor(int a) { count
= a; }< / font > < / tt > < / dir >
< a NAME = "classname" > < / a > < font size = +2 > Class name< / font >
< p > The class name is defined by the < tt > getClassName< / tt > method. This
is used to determine the name of the constructor.
< dir > < tt > < font color = "#006600" > public String getClassName() { return "Counter";
}< / font > < / tt > < / dir >
< a NAME = "Dynamic" > < / a > < font size = +2 > Dynamic properties< / font >
< p > Dynamic properties are defined by methods beginning with < tt > jsGet_< / tt >
or < tt > jsSet_< / tt > . The method < tt > jsGet_count< / tt > defines the < i > count< / i >
property.
< dir > < tt > < font color = "#006600" > public int jsGet_count() { return count++;
}< / font > < / tt > < / dir >
The expression < tt > c.count< / tt > in the JavaScript code above results in
a call to this method.
< p > < a NAME = "DefiningMethods" > < / a > < font size = +2 > Defining JavaScript "methods"< / font >
< p > Methods can be defined using the < tt > jsFunction_ prefix< / tt > . Here we
define < tt > resetCount< / tt > for JavaScript.
< dir > < tt > < font color = "#006600" > public void jsFunction_resetCount() { count
= 0; }< / font > < / tt > < / dir >
The call < tt > c.resetCount()< / tt > above calls this method.
< p > < a NAME = "AddingCounter" > < / a > < font size = +2 > Adding Counter to RunScript< / font >
< p > Now take a look at the < a href = "http://lxr.mozilla.org/mozilla/source/js/rhino/examples/RunScript4.java" > RunScript4
example< / a > . It's the same as RunScript except for two additions. The method
< tt > ScriptableObject.defineClass< / tt >
uses a Java class to define the Counter "class" in the top-level scope:
< dir > < tt > < font color = "#006600" > ScriptableObject.defineClass(scope, Counter.class);< / font > < / tt > < / dir >
Now we can reference the < tt > Counter< / tt > object from our script:
< dir > < tt > < font color = "#663366" > $ java RunScript4 'c = new Counter(3); c.count;
c.count;'< / font > < / tt >
< br > < tt > < font color = "#663366" > 4< / font > < / tt > < / dir >
It also creates a new instance of the < tt > Counter< / tt > object from within
our Java code, constructing it with the value 7, and assigning it to the
top-level variable < tt > myCounter< / tt > :
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #006600" >
Object[] arg = { new Integer(7) };
Scriptable myCounter = cx.newObject(scope, "Counter", arg);
scope.put("myCounter", scope, myCounter);
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
Now we can reference the < tt > myCounter< / tt > object from our script:
2002-07-09 21:49:16 +04:00
< blockquote >
< pre style = "color: #663366" >
$ java RunScript3 'RunScript4 'myCounter.count; myCounter.count'
8
< / pre >
< / blockquote >
2001-04-25 00:31:31 +04:00
< / body >
< / html >