Sharing Objects
In addition to sharing objects by passing arguments and retrieving returned values, JSR 223 offers another way to share objects using the Bindings object. A Bindings object is simply a map of key-value pairs that is maintained by the engine. You can place objects in the map using the put method and retrieve them using get. Objects in the map are accessible by both the Java program and the script. Unlike the Invocable interface, which is optional, the put and get methods of ScriptEngine must be implemented so sharing objects using Bindings can always be relied upon to work. ShareObjects.java (Listing Eleven) is a program this executes the Ruby script share.rb (Listing Twelve).
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ca.tremblett;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
*
* @author ptremblett
*/
public class ShareObjects {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("ruby");
try {
Double rand = new Double(0.0);
engine.put("randomNumber", rand);
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Iterator<Entry<String, Object>> it = bindings.entrySet().iterator();
System.out.println("Bindings follow:");
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("** end of bindings list **");
System.out.println("Generating 10 random numbers using script share.rb");
for (int i = 0; i < 10; ++i) {
engine.eval(new FileReader("scripts/share.rb"));
System.out.println(engine.get("randomNumber"));
}
}
catch (FileNotFoundException ex) {
Logger.getLogger(ShareObjects.class.getName()).log(Level.SEVERE, null, ex);
}
catch (ScriptException ex) {
Logger.getLogger(ShareObjects.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
$randomNumber = rand()
The following code in ShareObjects.java stores the java.lang.Double object referenced by the variable rand in the Binding object with the key randomNumber:
Double rand = new Double(0.0);
engine.put("randomNumber", rand);
We can satisfy ourselves that the key-value pair has been stored by executing the following code that retrieves and lists all of the engine's Bindings:
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Iterator<Entry<String, Object>> it = bindings.entrySet().iterator();
System.out.println("Bindings follow:");
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("** end of bindings list **");
If we examine share.rb, the script that our program will execute, we see that it contains the following single line of code:
$randomNumber = rand()
When this code executes, it stores the random number returned by Ruby's rand() function in the global variable $randomNumber. Notice that the variable has the same name as the key we used to store our java.lang.Double object.
Now let's execute the script 10 times using the following Java code:
for (int i = 0; i < 10; ++i) {
engine.eval(new FileReader("scripts/share.rb"));
System.out.println(engine.get("randomNumber"));
}
When we run the program, we see the following output displayed:
Bindings follow: randomNumber=0.0 ** end of bindings list ** Generating 10 random numbes using script share.rb 0.10022355384068038 0.046325867180632585 0.2985955622207479 0.4429729915177535 0.15434718054040764 0.24336547768828254 0.03702386758338283 0.2835491034756251 0.9940891729779046 0.9953925167840609
You can see that the list of key-value pairs in the bindings list consists of the single pair we added using the key randomNumber. You can also see that each of the 10 calls to the get method to retrieve the value of the object stored with the key randomNumber returns a different value, namey the value most recently stored in the global variable $randomNumber.
Conclusion
Before JSR 223, trying to coerce Java and scripting languages to work together involved everything short of bubble gum, bailing wire, and duct tape. Furthermore, techniques you used with one scripting language were different from those you used with another, making replacing one scripting language with another problematic. The examples presented here demonstrate that JSR 223 has made these problems a thing of the past and has delivered a mechanism that enables Java developers to expand their programming toolchest to include the power and flexibility offered by a wide variety of scripting languages.


