March 08, 2009
JSR 223: Scripting for the Java PlatformCalling Scripts From Java
Now that we know that several scripting engines are available, the obvious next thing we would like to do is write a Java program that runs a script written in the language each engine supports. Rather than use the traditional "Hello World", I chose to use the Trabb Pardo-Knuth (TPK) algorithm introduced by Luis Trabb Pardo and Donald Knuth in their 1977 work The Early Development of Programming Languages. The algorithm is as follows:
TPK.groovy (Listing Three), TPK.py (Listing Four), and TPK.rb (Listing Five) are implementations of the TPK algorithm written in Groovy, Python, and Ruby, respectively.
stdin = new BufferedReader(new InputStreamReader(System.in))
stdout = new BufferedWriter(new OutputStreamWriter(System.out))
def numbers = []
println "Enter number at each promnpt:"
for (i in 1..11) {
println ">"
x = stdin.readLine()
numbers.add(Integer.parseInt(x))
}
for (i in numbers.size-1..0) {
try {
println(numbers.get(i)+5*i**3)
}
catch (e) {
println("error")
}
}
Listing Three: Groovy
from math import sqrt
def f(t):
return sqrt(abs(t))+5*t**3
print "Enter a number at each prompt"
a = [int(raw_input(">")) for i in range(11)]
for i in range(10,-1,-1):
print "for x = ",i,"y ",
y = f(a[i])
if y > 400:
print "IS TOO LARGE"
else:
print "= ", y
Listing Four: Python
Listing Five: Ruby
JavaScriptingDemo.java (Listing Six) is a Java program that searches a directory named script for all files whose names are TPK.*; determines if an engine is found for the file's extension and, if an engine is available, invokes the engines eval() method passing as an argument a FileReader that can read a character stream from the file containing the script.
/* * To change this template, choose Tools | Templates and open the template in the editor. */ package ca.tremblett;
Listing Six
Running JavaScriptDemo produces the output in Listing Seven. If you run each of the three scripts from the command line, you should see the same output.
Running TPK.groovy using engine groovy Version 1.5.7 for language groovy Enter number at each promnpt: > 1 > 2 > 3 > 4 > 5 > 6 > 7 > 8 > 9 > 10 > 11 5011 3655 2569 1723 1087 631 325 139 43 7 1 ============================ *sys-package-mgr*: can't create package cache dir, '/Users/ptremblett/NetBeansProjects/JavaScriptingDemo/dist/lib/jython.jar/cachedir/packages' Running TPK.py using engine jython Version 2.2.1 for language python Enter a number at each prompt >1 >2 >3 >4 >5 >6 >7 >8 >9 >10 >11 for x = 10 y IS TOO LARGE for x = 9 y IS TOO LARGE for x = 8 y IS TOO LARGE for x = 7 y IS TOO LARGE for x = 6 y IS TOO LARGE for x = 5 y IS TOO LARGE for x = 4 y IS TOO LARGE for x = 3 y = 322.0 for x = 2 y = 136.73205080756887 for x = 1 y = 41.41421356237309 for x = 0 y = 6.0 ============================ Running TPK.rb using engine JRuby Engine Version 1.1.4 for language ruby Enter a number at each prompt >1 >2 >3 >4 >5 >6 >7 >8 >9 >10 >11 for x=11 result is too large for x=10 result is too large for x=9 result is too large for x=8 result is too large for x=7 result is too large for x=6 result is too large for x=5 result is too large for x=4 result is 322.0 for x=3 result is 136.73205080756887 for x=2 result is 41.41421356237309 for x=1 result is 6.0 ============================
Listing Seven
Invoking Functions In a Script
Sometimes you don't want to execute an entire script; instead, you want to execute a single function that it includes. The mechanism that provides this capability is the Invocable interface. The specification states that script engines are not required to support this interface. The Mozilla Rhino engine included in Java 6 does support it as does the JRuby engine I am using. Before writing code that invokes functions, you should verify that the engine for the language in which your script is written supports the Invocable interface.
HelloGoodbye.rb (Listing Eight) contains Ruby code that defines three functions: hello, goodbye, and wait.
Listing Eight
InvokeFunctions.java (Listing Nine) is a Java program that executes two of these three functions.
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package ca.tremblett;
Listing Nine
The relevant code is as follows:
As we did when I ran our three TPK scripts, I invoke engine.eval() but notice that it produces no output. Why not? Because the "execution" consists of simply defining functions. Next, I create an Invocable engine using casting. I then invoke the invocable engines invokeFunction() method passing as a single argument the name of the function we wish to invoke. When I run InvokeFunctions, it displays the following output:
Unlike hello and goodbye, the wait function defined in HelloGoodbye.rb takes an argument. PassArguments.java (Listing Ten) is a program that passes an argument to a function:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package ca.tremblett;
Listing Ten
The only difference between this program and InvokeFunctions.java is the addition of the following code:
Notice that the form of the invokeFunction() method used to call the wait function takes two arguments. The first is the name of the function and the second is the argument to be passed to the function. Also I call the wait function twice. The second call shows that not only can you pass an argument to a function but you can also obtain the value the function returns.
Finally, it is worth reiterating that everything discuss in this section is only possible if the implementation support the Invocable interface.
|
|
||||||||||||||||||||||||||||||
|
|
|
|