ProblemYou want to interface Java components to an existing scripting language. SolutionUse the Bean Scripting Framework (BSF). DiscussionMany scripting languages are used in the computing field today: VB, Perl, Python, JavaScript, Tcl/TK, REXX, and others. A project that originated at IBM but has now been taken over by the Apache Foundation, the Bean Scripting Framework (BSF), aims to provide a way to allow a number of scripting languages to interoperate with Java. The BSF consists of a management API, an engine API for driving different scripting languages, and a series of plug-ins for different scripting languages. The management API lets you either evaluate an expression in the given scripting language, such as "2+2" (which is so simple as to be valid in most supported languages), or run a script stored in a script file. In this example, I'll use Jython, a pure-Java (certified) implementation of the scripting language Python (see http://www.python.org and http://www.jython.org or the O'Reilly book Learning Python). While it is convenient (and efficient) to run Jython in the same JVM as the calling program, this is not by any means a requirement; for example, it is possible to use BSF with scripting languages written in some native language. BSF and the scripting plug-in are responsible for dealing with whatever "plumbing" external connections or processes this requires. Among others, BSF currently supports the languages listed in Table 26-1.
BSF could also support Mac OS Apple Scripting or almost any other language, although I don't know of an implementation at present. Example 26-5 uses Jython to evaluate and print the value of 22/7, a crude but time-honored approximation of Math.PI, using the management API's eval( ) function. The imports assume you are using BSF 2.3; prior to this, the namespace of com.ibm was used instead of org.apache. Example 26-5. BSFSample.javaimport org.apache.bsf.util.*; import org.apache.bsf.*; import java.io.*; /** Sample of using Bean Scripting Framework with Jython */ public class BSFSample { public static void main(String[] args) { BSFManager manager = new BSFManager( ); // register scripting language String[] fntypes = { ".py" }; manager.registerScriptingEngine("jython", "com.ibm.bsf.engines.jython.JythonEngine", fntypes); try { // try an expression Object r = manager.eval("jython", "testString", 0, 0, "22.0/7"); System.out.println("Result type is " + r.getClass( ).getName( )); System.out.println("Result value is " + r); } catch (Exception ex) { System.err.println(ex.toString( )); } System.out.println("Scripting demo done."); return; } } This program prints the following output: $ java BSFSample 'import exceptions' failed; using string-based exceptions Result type is org.python.core.PyFloat Result value is 3.142857142857143 Scripting demo done. $ The exceptions failure is probably due to my having installed Jython in a nonstandard location and not setting the environment variable(s) needed to find it. Further, the first time you run it, Jython spits out a bunch of nattering about your CLASSPATH, one line for each JAR file that it finds. These can be a bit surprising when they pop up from a script, but Jython doesn't seem to know or care whether it's being run interactively or dynamically: packageManager: processing new jar, "/usr/local/java/swingall.jar" The following longer example uses the LabelText bean from Recipe Recipe 23.8 and a push button to run a Python script that collects the text from the LabelText instance and displays it on the standard output. Here is the little script, buttonhandler.py: print "Hello"; print bean.getText( ); When I ran this, I typed the famous words that Alexander Graham Bell apparently sent to his assistant Watson and had the Java program send them to the Python script. Sure enough, when I clicked on the button, I got this on the standard output (as shown in Figure 26-2): Script output: --> Hello Mr. Watson, come here <-- End of Script output. Figure 26-2. BSFSample in actionNothing you couldn't do in Java, of course, but in this example, the LabelText bean is registered with the BSF as a bean, and the JButton 's action handler runs a script that gets that text and displays it. Example 26-6 shows the source code for the script-using program. Example 26-6. BSFAction.javaimport org.apache.bsf.util.*; import org.apache.bsf.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; /** Longer sample of using Bean Scripting Framework with Jython */ public class BSFAction { protected String FILENAME = "buttonhandler.py"; protected BSFManager manager; protected BSFEngine jythonengine; protected String language; protected String script; public static void main(String[] args) { new BSFAction( ); } BSFAction( ) { // Construct the Bean instance LabelText bean = new LabelText("Message to Python script"); try { manager = new BSFManager( ); // register scripting language String[] fntypes = { ".py" }; manager.registerScriptingEngine("jython", "com.ibm.bsf.engines.jython.JythonEngine", fntypes); jythonengine = manager.loadScriptingEngine("jython"); // Tell BSF about the bean. manager.declareBean("bean", bean, LabelText.class); // Read the script file into BSF language = manager.getLangFromFilename(FILENAME); script = IOUtils.getStringFromReader( new FileReader(FILENAME)); } catch (Exception ex) { System.err.println(ex.toString( )); System.exit(0); } System.out.println("Scripting setup done, building GUI."); final JFrame jf = new JFrame(getClass( ).getName( )); Container cp = jf.getContentPane( ); cp.setLayout(new FlowLayout( )); cp.add(bean); // add the LabelText JButton b = new JButton("Click me!"); cp.add(b); // and the button under it. b.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent evt) { try { // When the button is pressed, run the script. System.out.println("Script output: -->"); manager.exec(language, FILENAME, 0, 0, script); System.out.println("<-- End of Script output."); } catch (BSFException bse) { JOptionPane.showMessageDialog(jf, "ERROR: " + bse, "Script Error", JOptionPane.ERROR_MESSAGE); } } }); // A Quit button at the bottom JButton qb = new JButton("Quit"); cp.add(qb); qb.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent evt) { System.exit(0); } }); // Routine JFrame setup jf.pack( ); jf.setVisible(true); } } See AlsoInformation on the Bean Scripting Framework is located at the Jakarta Project's web site at http://jakarta.apache.org/bsf/. Many other projects aim to blend Java with other languages. As a single example, check out the Omega Project's interface at http://www.omegahat.org/RSJava/. R, itself a clone of S, is the statistical package used to produce the charts back in Figure 5-1. This interface lets you use Java inside R or S and to call R or S from Java code. |