mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
358 lines
14 KiB
HTML
358 lines
14 KiB
HTML
<!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>
|
|
<pre><font color="#663366">$ java RunScript "Math.cos(Math.PI)"
|
|
-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>
|
|
<pre><font color="#006600">Scriptable scope = cx.initStandardObjects(null);</font></pre>
|
|
</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.
|
|
<blockquote>
|
|
<pre style="color: #006600">
|
|
String s = "";
|
|
for (int i=0; i < args.length; i++) {
|
|
s += args[i];
|
|
}
|
|
</pre>
|
|
</blockquote>
|
|
<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>
|
|
<pre style="color: #006600">
|
|
} finally {
|
|
Context.exit();
|
|
}
|
|
</pre>
|
|
</blockquote>
|
|
exits the Context. This removes the association between the Context and
|
|
the current thread and is an essential cleanup action. There should be
|
|
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>.
|
|
<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:
|
|
<dir><tt><font color="#006600">Scriptable jsArgs = Context.toObject(System.out,
|
|
scope);</font></tt>
|
|
<br><tt><font color="#006600">scope.put("out", scope, jsArgs);</font></tt></dir>
|
|
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,
|
|
<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>
|
|
<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.
|
|
<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>
|
|
<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:
|
|
<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>
|
|
<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>
|
|
<pre style="color: #663366">
|
|
$ java -cp 'js.jar;examples' org.mozilla.javascript.tools.shell.Main
|
|
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
|
|
</pre>
|
|
</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>:
|
|
<blockquote>
|
|
<pre style="color: #006600">
|
|
Object[] arg = { new Integer(7) };
|
|
Scriptable myCounter = cx.newObject(scope, "Counter", arg);
|
|
scope.put("myCounter", scope, myCounter);
|
|
</pre>
|
|
</blockquote>
|
|
Now we can reference the <tt>myCounter</tt> object from our script:
|
|
<blockquote>
|
|
<pre style="color: #663366">
|
|
$ java RunScript3 'RunScript4 'myCounter.count; myCounter.count'
|
|
8
|
|
</pre>
|
|
</blockquote>
|
|
|
|
</body>
|
|
</html>
|