JudoScript.COM Design principles of Judo the sport and the language
HomeJudo LanguageJuSP PlatformJamaica Language 
Judo ReferenceJuSP ReferenceWiki/WeblogTutorials/PresentationsDownloadsGoodiesFeedback  
Article: Embed JudoScript In Java
 








This article is old and is being consolidated into the book.
Please refer to the corresponding chapter(s) therein.
If the chapters or sections are not completed yet, you can use this article.
Refer to the examples as they are tested against the latest code.

Table Of Content

  1. Bean Scripting Support
  2. JudoScript Java Engine
    » Single Script Many Instances
  3. Code Listings

Embed JudoScript In Java

By James Jianbo Huang    December 2001       printer-friendly version

Abstract   Two ways to embed JudoScript in Java: through its support of Bean Scripting Framework and its own, simpler engine interface. JudoScript is designed for Java, using Java is intrinsic. The only issue regarding embedding in Java is passing Java objects between Java code and the script. IBM's Bean Scripting Framework (BSF) is a popular interface for this purpose. It also supports event handling of beans by scripts, a feature not needed here. BSF support is significant because there are Java applications, such as Ant, use this bridge to embed a number of BSF-supporting scripting languages. However, if you intend to use just JudoScript for your embedded scripting needs, JudoScript has a simpler and lighter-weight interface. You don't need any extra packages (BSF, that is). You can also parse a script and run in multiple engines in their own Java threads.


 

1. Bean Scripting Support

The Bean Scripting Framework (BSF) is a popular architecture for incorporating scripting languages (not necessarily written in Java) into Java software. The key features are: a) pass Java objects, or beans, between Java and scripts, and b) allow script code to handle Java bean events. For many scripting languages written in Java, the second part is not used because once they get hold of a Java object, they can handle events by themselves. To these scripting languages, all they need is BSF's mechanism to pass Java objects around. This is exactly what JudoScript uses BSF for.

Download the BSF, put its jar file in your classpath along with JudoScript's, and with just a little extra coding, your Java software will have embedded scripting capability. This is how.

Listing 1. BSFTest.java
 1: import java.awt.Frame;
 2: import java.io.FileReader;
 3: import com.ibm.bsf.*;
 4: import com.ibm.bsf.util.*;
 5:
 6: public class BSFTest
 7: {
 8:   public static void main (String[] args) throws Exception
 9:   {
10:     // 1. Register judoscript to BSF
11:     BSFManager.registerScriptingEngine(
12:       "judoscript", "com.judoscript.BSFJudoEngine", new String[]{"judo","jud"} );
13:
14:     String fileName = "randgen.judo";
15:
16:     // 2. Create a BSF manager
17:     BSFManager manager = new BSFManager();
18:
19:     // 3. Create an object to pass on to the script
20:     Frame frame = new Frame();
21:     manager.declareBean("frame", frame, Frame.class);
22:
23:     try {
24:
25:       // 4. Invoke judoscript
26:       manager.exec(manager.getLangFromFilename(fileName), fileName, 0, 0,
27:                    IOUtils.getStringFromReader(new FileReader(fileName)));
28:
29:       // 5. Get back an object from judoscript
30:       String title = (String)manager.lookupBean("title");
31:
32:       // 6. Show the frame
33:       frame.setTitle(title);
34:       frame.show();
35:
36:     } catch(BSFException be) {
37:       System.out.println("exception: " + be.getMessage());
38:       Throwable oe= be.getTargetException();
39:       if(null != oe)
40:         System.out.println("\nOriginal Exception:"+ oe.getMessage());
41:       be.printStackTrace();
42:     } catch(Exception e) {
43:       e.printStackTrace();
44:     }
45:   }
46: }

The BSF package has predefined a number of scripting language engines. When a script is being loaded, the file extension is used to identify the language. JudoScript is not listed as a default languages yet; it is possible to add it to the com/ibm/bsf/Languages.properties file. Programmatically registering (lines 11 through 12) is just as easy. To use a scripting language, get an BSFManager first (line 17).

This is an AWT application just for exercise. It passes a Java object to the script (lines 20 through 21), and obtains a Java object created in the script (line 30), and starts the GUI (lines 33 through 34). On line 33, the frame is actually running with event handlers set up in the script, and it contains components created in the script. Here is the script.

Listing 2. randgen.judo
 1: standalone = (frame == null); // frame may be set in Java!
 2:
 3: if standalone {
 4:   frame = javanew java.awt.Frame('RandGen - standalone JudoScript');
 5: } else { // embedded -- pass 'title' back to Java
 6:   {
 7:     $$bsf.registerBean("title", 'RandGen - JudoScript thru BSF');
 8:   catch: // if not BSF
 9:     ::title = 'RandGen - JudoScript in Java';
10:   }
11: }
12:
13: result = javanew java.awt.TextField("0");
14: button = javanew java.awt.Button('next');
15: frame.resize(400, 100);
16: frame.add("North", result);
17: frame.add("Center", button);
18: if standalone { frame.show(); }
19:
20: // *** handle data entry keys
21: guiEvents {
22: < frame : Window : windowClosing   >: exit 0;
23: < button: Action : actionPerformed >: result.text = rand(0,100);
24: }

Interestingly, this script can be run stand-alone, embedded by BSF, or embedded by the JudoScript engine introduced later. The key is the frame variable. At the very beginning, if it is set by the host, this program is being embedded. Otherwise, a new frame is created (line 4). An event handler is assigned to it (line 22), no matter how it is created, and a number of components are added to it (lines 16, 17).

JudoScript interacts with BSF through the built-in variable, $$bsf. If it is not defined, calling its method will exception (lines 7, 8). Line 7 calls its registerBean() method to pass back an object; find information about this and other methods in the BSF API documentation.

The following program loads a function created by the Java code, and then calls it. On line 14 it obtains a JudoScript BSF engine; this is reasonable because we are going to load JudoScript code (line 19).

Listing 3. BSFCallTest.java
 1: import com.ibm.bsf.*;
 2: import com.ibm.bsf.util.*;
 3:
 4: public class BSFCallTest
 5: {
 6:   public static void main (String[] args) throws Exception
 7:   {
 8:     // 1. Register judoscript to BSF
 9:     BSFManager.registerScriptingEngine(
10:       "judoscript", "com.judoscript.BSFJudoEngine", new String[]{"judo","jud"} );
11:
12:     // 2. Create a BSF manager and obtain the engine
13:     BSFManager manager = new BSFManager();
14:     BSFEngine engine = manager.loadScriptingEngine("judoscript");
15:
16:     try {
17:
18:       // 3. Create a JudoScript function
19:       engine.exec(null,0,0,"function foo a,b { return a+b; }");
20:
21:       // 4. Call the function
22:       Object[] params = new Object[] { new Integer(1), new Double(2) };
23:       System.out.println( engine.call(null,"foo",params) );
24:       params[1] = new Integer(2);
25:       System.out.println( engine.call(null,"foo",params) );
26:
27:     } catch(Exception e) { e.printStackTrace(); }
28:   }
29: }

 

»»» Top «««

 

2. JudoScript Java Engine

JudoScript provides an engine for Java programs to embed it. It is much simpler because all it has to support is passing Java objects between the two parties and execute the scripts. The class is com.judoscript.JudoEngine, whose methods are:

public void putBean(String name, Object value);
public void clearBean(String name);
public Object getBean(String name);
public void runScript(Object script);
public void runScript(String path);
public void runCode(String code);
public Object call(String fxn, Object[] params);
public static Object parseScript(Script path);
public static Object parseCode(String code);
A Java object can be put into the engine to be used by subsequent runs of a script. When a script is run, its functions and other declarations stays until the next run. Use the call() method to invoke a function. These mechanisms should suffice for Java/JudoScript interactions.

The following program does the same as the above BSFTest example.

Listing 4. EmbedTest.java
 1: import java.awt.Frame;
 2: import com.judoscript.JudoEngine;
 3:
 4: public class EmbedTest
 5: {
 6:   public static void main (String[] args) throws Exception
 7:   {
 8:     // 1. Create a JudoScript engine
 9:     JudoEngine je = new JudoEngine();
10:
11:     try {
12:
13:       // 2. Create an object to pass on to the script
14:       Frame frame = new Frame();
15:       je.putBean("frame", frame);
16:
17:       // 3. Invoke judoscript
18:       je.runScript("randgen.judo");
19:
20:       // 4. Get back an object from judoscript
21:       String title = (String)je.getBean("title");
22:
23:       // 5. Show the frame
24:       frame.setTitle(title);
25:       frame.show();
26:
27:     } catch(Exception e) { e.printStackTrace(); }
28:   }
29: }

The objects that Java passes to JudoScript and those that JudoScript intends to expose to Java are all in the root context. See line 9 in listing 0.

The following example creates a JudoScript function (line 13) then invokes it (lines 17, 19):

Listing 5. CallTest.java
 1: import com.judoscript.JudoEngine;
 2:
 3: public class CallTest
 4: {
 5:   public static void main (String[] args) throws Exception
 6:   {
 7:     // 1. Create a JudoScript engine
 8:     JudoEngine je = new JudoEngine();
 9:
10:     try {
11:
12:       // 2. Create a JudoScript function
13:       je.runCode("function foo a,b { return a+b; }");
14:
15:       // 3. Call the function
16:       Object[] params = new Object[] { new Integer(1), new Double(2) };
17:       System.out.println( je.call("foo",params) );
18:       params[1] = new Integer(2);
19:       System.out.println( je.call("foo",params) );
20:
21:     } catch(Exception e) { e.printStackTrace(); }
22:   }
23: }

Single Script Many Instances

To parse a script then run multiple instances in different threads, call the parseScript() or parseCode() method, then pass the returned script object to multiple JudoEngine instances.

 

»»» Top «««

 

3. Code Listings

  1. BSFTest.java
  2. randgen.judo
  3. BSFCallTest.java
  4. EmbedTest.java
  5. CallTest.java




Copyright © 2001-2005 JudoScript.COM. All Rights Reserved.