|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON General Java BeanShell & DynamicJava: Java Scripting with Java
BeanShell & DynamicJava: Java Scripting with Java
By: Rick Hightower
Jul. 1, 2000 12:00 AM
The past three articles in this series have highlighted the strengths of scripting languages. They're interactive and dynamic, and allow you to experiment, debug and prototype solutions quickly. However, the most common response when I speak to die-hard Java fanatics is, "Yeah, but I'll have to learn another language and I already know Java" (I consider myself a die-hard Java fanatic to a degree). To be honest, this is a barrier that most won't cross. But what if you could have the best of both worlds? What if you could have your cake and eat it too? Well, in a sense you can. You can use a Java-like scripting language. Now when I say that, most of you were probably thinking JavaScript. (Admit it.) But I'm not talking about JavaScript. Java and JavaScript have a similar syntax, both deriving from C/C++. However, the way that JavaScript defines methods, event handlers and classes is quite different from Java. In fact, other than the similar names and common C heritage, JavaScript and Java have little in common. (Consider the inheritance by prototype model by JavaScript versus the more common inheritance model found in Java. However, Rhino is a good marriage of Java and JavaScript. ) If you know Java, learning JavaScript syntax will take a while, but not too long. However, you don't have to learn another syntax to get the advantages of a dynamic scripting language. Several scripting languages are heavily based on the Java syntax. Two of the most popular, BeanShell and DynamicJava, are interpreted versions of Java. Both have interactive interpreters that allow experimenting with Java APIs. Both closely follow the Java syntax. (DynamicJava is much closer.)
BeanShell Background One advantage of BeanShell over plain Java is you can use BeanShell interactively for Java experimentation and debugging. BeanShell, which is easy to embed, can be used as a scripting engine for your applications. Not surprisingly, the author of BeanShell compares the relationship of Java and BeanShell to the relationship of C and Tcl/TK. The name BeanShell has always kind of thrown me for a loop. When I first looked into it (almost two years ago), the name made me think of C Shell or KornShell, command interpreters (shells) for the UNIX world. Somehow the name seems to be related to shell scripting, although BeanShell has little to do with KornShell and more to do with Python, Perl and Tcl. That said, BeanShell does have some UNIX-like shell commands as follows: cd(), cat(), dir(), pwd(), rm(), exec(), and so on. Unlike DynamicJava, BeanShell supports scripted objects as simple method closures like those in JavaScript (see Part 1 of this series [Vol. 5, issue 2] for examples of JavaScript method closure). DynamicJava uses the Java syntax for adding methods to a class. BeanShell closely mimics the Java language. For example, it uses the full Java statements and expressions syntax. It emulates strongly typed variables and methods. It mimics Java operators (arithmetic, logical and bitwise). BeanShell could aptly be renamed little Java. It closely follows the syntax of the language in many respects. It also adds features that are essential to a scripting language. For example, it allows dynamically typed (untyped) variables. It has the following scripting features: methods with optionally loose typing of arguments and return values, scripted objects with JavaScript-like method closures, and scripted AWT/Swing event handlers. Like JPython, BeanShell has convenience syntax for working with JavaBean properties. It also has many utilities for working with beans, e.g., loading a bean (load) and saving a bean (save(bean)). In addition, BeanShell has simplified ways for working with primitive wrapper types and hashtables. One BeanShell claim to fame is that it has such a small footprint - less than 150K.
DynamicJava Background
Rosetta Stone Examples
Installing BeanShell Thus, to set up the classpath, you can do the following: UNIX: export CLASSPATH=$CLASSPATH: usr/rickh/BeanShell/bsh- 1.0.jar Windows: set classpath=%classpath%;c:\BeanShell\bsh-1_0.jar If you're using a version of Java that doesn't include Swing, you need to add the swingall JAR file to the classpath as well. Some of the BeanShell utilities use Swing. Once you set up the classpath, you can start BeanShell in a graphical interactive interpreter or a console interactive interpreter. To start BeanShell in a GUI interactive interpreter, do this: java bsh.Console or run as text-only on the command line: java bsh.Interpreter
The graphical interpreter isn't that graphical.
BeanShell 101: A Simple "Class" The example below defines an Employee "class" in BeanShell:
Employee (){
__init(){ For comparison, the equivalent Java Employee class would be defined as follows:
public class Employee{
private Employee manager;
public Employee(){
... Notice that the use of super in the BeanShell class isn't the same as it is in Java. In BeanShell it refers to the method that contains the current method. Thus super in the _init method refers to the Employee instance namespace - weird. Also notice that the manager variable in the BeanShell class is untyped, which means we can assign it later to any type. Compare the BeanShell Employee "class" in Listing 1 to roughly the equivalent Java class in Listing 2. As you compare the two listings, notice that they both define toString methods. Also notice that, with the BeanShell "class," methods, arguments and return types don't have to be typed. Be sure to compare the getManager method in both the BeanShell version and the Java version. To create an instance of an Employee and print it to the screen, you'd do the following: print(Employee().toString()); The equivalent Java statement would be: System.out.println(new Employee()); You can use Java objects in BeanShell, and if you use the Java Employee class in the BeanShell script, you can use the same syntax that you'd use in Java in BeanShell. Thus BeanShell allows you to do object composition with its Object scripting and to work with Java classes as you would in Java. The toString isn't recognized as a special method as it is in Java (for Object scripting). Next we create two instances of employee called joe and ron and print those employees to the console. We print joe, who is ron's manager, by invoking the getManager method of ron - first in BeanShell, then in Java.
BeanShell:
Java: As I said, the syntax is similar but not identical. Again, if you used a true Java Employee class, the code for Java and BeanShell would be identical. But I wanted to compare the way that BeanShell defines "classes" with the way that Java does.
A Simple GUI If you have BeanShell installed, let's pretend we're prototyping this GUI. Fire up the interactive interpreter by typing java bsh.Console as the system prompt. (You can opt to follow along in the DynamicJava interactive interpreter; it should work out just as well.) Import the JFrame from the javax.swing package. bsh % import javax.swing.JFrame; (Note that the bsh % is the BeanShell prompt, i.e., you don't need to type bsh % each time.) Create an instance of the frame, set its size to 200 by 200 and make it visible. First create an instance. bsh % frame = new JFrame("My Prototype"); There's a convenient way to set the frame's visible property. (Note that this can be used to set properties dynamically from a configuration file.) bsh % frame{"visible"}=true; You can also use the Java way to set the visible property to true. bsh % frame.setVisible(true); Now set the size of the frame to 200 by 200. bsh % frame.setSize(200,200); Note: If you remember the JPython article (JDJ, Vol. 5, issue 3), the foregoing three steps were done in one line of code. In BeanShell any bean property of a class can be set wth the bean{"property_name"}=value syntax. By bean property I mean a property as defined by a getter and a setter method, that is, the bean "design pattern" for properties. At this point all we have is a stupid-looking gray box. Let's add some components to it - some labels, text fields and an okay button. As we develop this GUI application, I'll point out some of the features of BeanShell. (Since this is a demo, we're not going to meet any GUI style guidelines.) First we need to import a few classes from javax.swing.
bsh % import javax.swing.JButton; We could have used the * syntax; for example, we could have said import javax.swing *; similar to the way you'd do it in Java. Next, create a pane (JPanel instance) and add it to the frame. Before we do this let's invoke the show command, which will show us what is returned from expressions.
bsh % pane = new JPanel(); The foregoing prints:
<javax.swing.JPanel[,0,0,0x0,invalid Now we want to add components to this pane using the GridBag layout. If this isn't familiar to you, it'll be good practice. First import the GridBag layout classes.
bsh % import java.awt.GridBagLayout; Next, change the layout of the pane to an instance of GridBagLayout. bsh % pane.setLayout(new GridBagLayout()); Now add the first component to the pane using a GridBagConstraint - a JLabel. This will use all of the default values of the GridBagConstraints (see Figure 1).
bsh % GridBagConstraints constraint = new GridBagConstraints(); Now add another JLabel, the label on the second row of the grid.
bsh % constraint.gridy=1; Add a text field on the first row in the second column. Then pack the frame (see Figure 2).
bsh % name = new JTextField(25); Now add a second text field for the employee ID, this time to the right on the second row. Then pack the frame.
bsh % id = new JTextField(10); As you can see, this isn't what we want. The text field components are centered and look silly (see Figure 3). I forgot to align the text field to the left in their cells (not really - I forgot on purpose). Let's remove the components, then add them back with the proper alignment (see Figure 4). See how useful it is to be able to experiment with the layout in the interactive interpreter? Remove the ID and name.
bsh % pane.remove(id); Now add back the ID and name with the proper alignment.
bsh % constraint.anchor=GridBagConstraints.WEST; //anchor West The above demonstrates the interactive, experimental environment in BeanShell. You can explore the cause and effect without the normal recompile, retest environment. Also, you can do this in a very Java-like syntax so when you're ready to write the real version there won't be much conversion. Bean events are easily handled in BeanShell. Just as with bean properties, BeanShell adds features to make event handling easier. To handle an event simply define the appropriately named method from the java.awt.event listener interface and register the corresponding "this" type reference with the component. Unlike Java, the "this" keyword means current namespace and the "super" keyword means the encasing namespace. To demonstrate this, let's set up an okay button. When the okay button gets clicked, this prototype application will print out the employee's name and ID. First create and add a button to the GUI (see Figure 5).
bsh % okay = new JButton("Okay"); Next, create a function. The function prints out the value of the name and ID text. Then register the current namespace with the okay button's actionListener.
bsh % actionPerformed( event ) { Enter some text in the Name and ID field and hit the okay button. This is a simple session, creating a simple GUI. For those of you who followed along with BeanShell, let me know what you think of it. I'm new to BeanShell, but I like it.
Rosetta Stone GUI Listing 3 shows the employee form that we prototyped in the interactive interpreter. Listing 4 shows the Java version of that prototype. If you compare the two, you'll notice they're very similar. Some notable differences are that the BeanShell version doesn't have a true class definition. Instead, it has some nested methods. Also, the BeanShell version of the "class" doesn't have a constructor or a main method. It took me about two minutes to convert the Java version to BeanShell. Since BeanShell is a subset of Java, the rest of the Rosetta Stone examples would be quite meaningless, that is, we already highlighted the major differences between BeanShell and Java.
DynamicJava and the Rosetta Stone Examples
Rosetta Stone Adding BeanShell in Java
import bsh.Interpreter; //Import the BeanShell Interpreter
Scorecard AUTHOR'S SCORECARD FOR BEANSHELL
AUTHOR'S SCORECARD FOR DYNAMICJAVA
Thus I give both scripting languages a score of 52 out of 80 based on the above criteria. Now remember, those criteria are based on a scripting-language philosophy of keeping things easy for the developer (see JDJ, Vol. 5, issue 2, for more information on the power of scripting languages). Drop by the JDJ Forum to grade BeanShell and DynamicJava. Let's drill down on the above criteria a bit.
Scripting languages are good for prototyping and rapid application development (refer to first article in series). Most Java developers don't want to learn new language syntax to get the advantage of scripting languages. DynamicJava and BeanShell fill a gap. I think BeanShell has the advantage over DynamicJava in that its creator wants to see it evolve into a better scripting language. For example, he wants to add support for regular expression. On the other hand, the creator of DynamicJava just wants to be syntax compatible with Java as much as possible. I think that BeanShell and DynamicJava have a long way to go to get to the levels of mature scripting languages. DynamicJava won't add more features to make it easier on the programmer, that is, more scripting-like (see interview with creator of DynamicJava). I think if BeanShell added the features that make JPython work so well with Java it would be much better. BeanShell syntax is more in tune with what people are used to (more so than NetRexx and JPython); it's Java-like. The JPython feature set is more in tune with what a scripting language should be. Combine them and throw in a few cool NetRexx features for good measure and you'd have one lean, mean, Java-like scripting language. NetRexx and JPython are mature scripting languages - more mature than BeanShell - but BeanShell has quite a niche (being more like Java). Components need scripting languages. ActiveX has Visual Basic. JavaBeans has BeanShell. LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK SPONSORED BY INFRAGISTICS
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||