forked from mozilla/rhino
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtutorial.html
More file actions
336 lines (307 loc) · 14.3 KB
/
tutorial.html
File metadata and controls
336 lines (307 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
<!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><tt><font color="#006600">String s = "";</font></tt>
<br><tt><font color="#006600">for (int i=0; i < args.length; i++)</font></tt>
<br><tt><font color="#006600"> s += args[i];</font></tt></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><font color="#006600">Context.exit();</font></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>.
<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><tt><font color="#663366">$ java RunScript3 'x = 7'</font></tt>
<br><tt><font color="#663366">x = 7</font></tt>
<br><tt><font color="#663366">f is undefined or not a function.</font></tt>
<br><tt><font color="#663366">$ java RunScript3 'function f(a) { return
a; }'</font></tt>
<br><tt><font color="#663366">x is not defined.</font></tt>
<br><tt><font color="#663366">f('my args') = my arg</font></tt>
<br><tt><font color="#663366"></font></tt> </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.
<dir><tt><font color="#006600">Object x = scope.get("x", scope);</font></tt>
<br><tt><font color="#006600">if (x == Scriptable.NOT_FOUND)</font></tt>
<br><tt><font color="#006600"> System.out.println("x
is not defined.");</font></tt>
<br><tt><font color="#006600">else</font></tt>
<br><tt><font color="#006600"> System.out.println("x
= " + Context.toString(x));</font></tt>
<br><tt><font color="#006600"></font></tt> </dir>
<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:
<dir><tt><font color="#006600">Object f = scope.get("f", scope);</font></tt>
<br><tt><font color="#006600">if (!(f instanceof Function))</font></tt>
<br><tt><font color="#006600"> System.out.println("f
is undefined or not a function.");</font></tt>
<br><tt><font color="#006600">else {</font></tt>
<br><tt><font color="#006600"> Object functionArgs[]
= { "my arg" };</font></tt>
<br><tt><font color="#006600"> Object result = ((Function)
f).call(cx, scope, scope, functionArgs);</font></tt>
<br><tt><font color="#006600"> System.out.println("f('my
args') = " + Context.toString(result));</font></tt>
<br><tt><font color="#006600">}</font></tt></dir>
<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><font 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</font></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>:
<dir><tt><font color="#006600">Object[] arg = { new Integer(7) };</font></tt>
<br><tt><font color="#006600">Scriptable myCounter = cx.newObject(scope,
"Counter", arg);</font></tt>
<br><tt><font color="#006600">scope.put("myCounter", scope, myCounter);</font></tt></dir>
Now we can reference the <tt>myCounter</tt> object from our script:
<dir><tt><font color="#663366">$ java RunScript3 'RunScript4 'myCounter.count;
myCounter.count'</font></tt>
<br><tt><font color="#663366">8</font></tt></dir>
</body>
</html>