|
|
|||||||||||||||||||
by Joshua Marinacci
| |||||||||||||||||||
| ||||||||||||
What do you think of when I say "scripting?" If you are a programmer, you might think of using Bash or Perl to automate command-line programs. If you are a designer, you may think of DHTML and JavaScript for building web pages. Either way, you probably don't think of graphical desktop applications, and you certainly don't think of Java. In years past, very few desktop applications had any support for internal scripting. Word had VBScript and Emacs had Lisp macros, but that was pretty much it. Today as Java developers, however, we have a wide variety of languages available to be easily embedded into our applications. By the end of this article, you will have a fully running Java program with an embedded JavaScript interpreter, and know enough to add scripting to your own applications.
The key to scripting languages is that they are designed for ad hoc programming: building small programs, or parts of programs, with quick turnaround. Common scripting language traits like loose typing, interpreting instead of compiling, and easy binding to other languages are all in support of ad hoc programming.
Scripting languages are most commonly used in two scenarios. One is to tie different components written in different languages together. These components could be modules like in Perl and TCL, or entire programs (like the many Unix command-line utilities) tied together with shell scripts. The second use is to extend a single program in a controlled manner. This second use is more commonly done by a person with lesser programming skills or without access to the source of the underlying application, and it is this scenario that we will discuss.
By creating a scripting layer to your application, you can allow semi-skilled developers to extend your program in ways that you don't have the time or expertise to do. Providing scripting support to your users isn't the easiest thing in the world; after all, you are potentially exposing the internals of your program to your users. But doing so can give your users great flexibility and power. Scripting will let you provide a better product for your customers and make them happy, and in the end, happier customers can only be a good thing.
If you are a regular reader of java.net, you may have noticed a recent poll asking readers what scripting language they would like to see embedded in Java. The most popular was JavaScript, closely followed by Python/Jython. I chose JavaScript because it fits our task--to extend a single program cleanly--very well. There are more people writing in JavaScript than probably any other language (except maybe Excel functions). Though Perl is more commonly used by professional programmers, there are many more non-professional programmers doing simple but useful things with JavaScript.
Don't believe me? Think of all of the web sites that use JavaScript. Not just the professional sites that use prefab libraries, but also the one-off pages done by complete novices. A little validation here, a bit of animation there; it's all done in JavaScript. Now think of Konfabulator and Apple's upcoming Dashboard. These are applications designed from the ground up to allow novice programmers to build simple but attractive systems. And their language of choice is JavaScript. Simple snippets of JavaScript are used everywhere, and by supporting JavaScript we can instantly take advantage of that shared knowledge among our users. It may not be the choice of skilled programmers (after all, I wouldn't use JavaScript to parse my web server logs or do automated backups), but for our target audience, non-professional programmers, it's the best thing out there.
There is pretty much only one JavaScript library for Java: Mozilla's Rhino. Rhino was spun off from a canceled project to rewrite Netscape Navigator entirely in Java. As their web page says: "When Netscape stopped work on 'Javagator', as it was called, somehow Rhino escaped the axe (rumor had it that the executives 'forgot' it existed).".
Though there is only one library, there are two ways to use it. You can write directly to the Rhino API or you can use the Bean Scripting Framework, also known as BSF. BSF is a generic framework built by IBM's AlphaWorks team to provide support for scripting Java using any language. This means that if you code against BSF, then you can swap in any scripting language you want with no code modifications. Currently BSF has built-in support for JavaScript, Python, Tcl, NetRexx, and XSLT, in addition to support for Java, Ruby, JudoScript, Groovy, and ObjectScript via third party libraries. BSF was originally built as a research project at IBM, but was donated to the Apache Jakarta project in 2002, where it resides today. We will be using BSF for this project so that you can swap in another language after the program is built.
To get started with scripting, you will first need to download the latest versions of BSF and Rhino. BSF is available here. The latest version of Rhino does not work with the latest release version of BSF (v2.3.0rc1), so you should download Rhino 1.5R3 (or check out a newer version of BSF from CVS). Drop the .jars from Rhino and BSF (bsf.jar and js.jar) into your classpath, and you are good to go.
Let's start with a simple example. Create a new class called
BSFJavascriptTest that looks like this:
import org.apache.bsf.*;
public class BSFJavascriptTest {
public static void main(String[] args) throws Exception {
BSFManager mgr = new BSFManager();
mgr.registerScriptingEngine("javascript",
"org.apache.bsf.engines.javascript.JavaScriptEngine",
null);
BSFEngine engine = mgr.loadScriptingEngine("javascript");
Object return_value = engine.eval("asdf",10,10,"4+5");
System.out.println("got: " + return_value);
}
}
As you can see, it's ridiculously simple. The first line of main creates
a new BSFManager. The second line uses the
BSFManager to register a specific scripting language
implementation, much as you would specify a JDBC driver. In this case, we
are loading the JavaScript framework and naming it
"javascript". The next line creates a
BSFEngine, the object that actually interprets the scripts.
Finally, we evaluate our expression "4+5" and print
out the return value: '9'. The other three arguments to
eval: "asdf", '10', and
'10', are to specify the name of the code and the line and
column numbers in the source code, which are used for printing out errors.
Since we are loading code from a script file, we don't really care about
these values. Just put in whatever you want. If you run this program you
will get the value : 9.
Let's try applying this to something more useful. When planning this article, I wanted to build an application that was fun and would let a novice programmer do something useful with small amounts of scripting. Thinking back to my days with graphing calculators, I came up with the idea of a particle simulator.
A particle simulator is a piece of software used to simulate a dynamic system, like a volcano or birds in flight. Originally invented for scientific use, they can also be amusing toys for playing with algorithms and creating pretty pictures. Though they vary greatly, all particle simulators work basically like this:
Very simple rules (like particle.x = Sin(time)) can
create very complex and beautiful behavior, not to mention be entertaining
for hours.
Simulators are usually written in two parts. One is the infrastructure that takes care of looping, drawing, and managing the objects. The other part consists of the actual rules that control how the particles move. These rules are usually simple, but require lots of tweaking, making them a perfect place to use scripting. In our program, the Java code handles all of the grunt work and leaves just the particle rules to JavaScript.
To combine the scripting and Java sides, I have created a program called SimEditor, which is shown in Figure 1.

Figure 1. SimEditor running
SimEditor displays the running simulation and includes a few
controls on the left. On the right are three text areas for writing scripts: one for creating new
particles, one for updating the particles, and one for drawing the
particles. A more sophisticated version of SimEditor would provide a real
code editor with syntax highlighting and code completion, but to keep this
simple, I've just used JTextAreas in scroll panes. The
underlying Java code manages the drawing canvas, starting and stopping the
threads, and loading code samples. To communicate with the scripting side,
there is a SimFrame interface with three methods for creating,
updating, an drawing particles. It is this interface that will be our
gateway to the scripting side.
Pages: 1, 2 |
View all java.net Articles.
|
|