Scripting Engines: The Process Flow
A standard architecture for the flow of control between an application and a scripting engine is shown in Figure 1
|Figure 1. Embedding the Engine: The diagram shows how a scripting engine can be embedded into an application using proxy objects.|
The application hosts a scripting engine. The application provides the engine with a set of scripts, which it then compiles into its script context. When the user instructs the application to execute a command that is implemented by a macro, the application follows this workflow:
- It sets up the script environment with proxy objects that represent the relevant portions of the application's object model.
- The scripting engine is instructed to execute the method or function that corresponds to the application event.
- The running script then implements the appropriate command behavior by using the proxy objects to modify the application object model.
- The method or function in the script ends and control is returned to the application.
This sequence is exactly what Microsoft Word and Excel do when they execute a macro.
Another common use for a scripting engine is for providing a modular extension mechanism. One classic example is an application that uses scripts to provide a customer with extensible input or output mechanism (see Figure 2).
|Figure 2. Translation: In this architecture the scripting engine acts as a translation mechanism.|
In this architecture the application uses the script as an extensible data translation mechanism. A practical example would be an Address Book application. The application can ship with several canned import mechanisms for the most common data sources, but it can also ship with an extensible scripting mechanism that the customer can use to build support for any data source.
One small tweak in this model is the removal of the proxy objects. None of the scripting engines demonstrated in this article are dependent on proxy objects; they are strictly optional. They use Java's reflection capability to talk directly to any object. Proxies are not required as they are when integrating C++ object models with scripting engines. Proxies do provide value in that they restrict the access that a script can have to the object model. So while they are not necessary, proxies may help you sleep a little better at night, knowing that your customers don't have access to every method in your object model.
Evaluating Scripting Engines
What are we looking for in a scripting engine?
- The scripting syntax should be familiar and simple.
- The language should be latently typed to make it easier for customers (and developers) to use.
- There should be a way to inject objects into the script context.
- The script should be able to read and write data and invoke methods on the injected objects.
- The injected objects should appear and work naturally within the language.
- There should be robust error handling to make it easy to debug the scripts.
- It should be easy to print out debug messages in case debugging is necessary and there is no support for single-step debugging.
- The engine should be thread-safe and provide for multiple script contexts.
- The engine and language should be powerful enough to talk to frameworks outside of the application. This allows the script to act as a bridge between applications.
The three scripting engines in this article meet and exceed these criteria. So let's get introduced:
- JythonThis is a Java implementation of the very popular Python programming language. The engine provides access to the power of Python and its code base as well as seamless access to any of the Java framework APIs. It's a highly evolved project (now in version 2.1), with a stable, well-tested code base. O'Reilly publishes a book specifically on Jython as well as the fundamental resource Programming Python.
- BeanShellThis language is similar in form and syntax to Java, which makes it an ideal language for developers. The BeanShell interpreter is loosely typed by default but can be set to support only strongly typed macros where variables are predefined. Like Jython, the BeanShell interpreter is actively developed and extremely stable. The language syntax is amply documented on the BeanShell Web site, as is the JavaDoc of the interpreter's API. BeanShell also has the advantage of being contained within a single .jar file, which makes it very easy to integrate.
- GroovyGroovy's fan base is growing fast thanks to a very clean syntax, similar in many way to the popular Ruby programming language. Groovy is attempting to make a standard of itself as JSR 241. Groovy is still an emerging language, but it has a novel syntax and a lot of a promise.
Now that you know a little about the scripting engines, I can introduce the example application, a flexible spam killer.