|
To install as an extension place the bsh.jar file in your $JAVA_HOME/jre/lib/ext folder. (OSX users: place the bsh.jar in /Library/Java/Extensions or ~/Library/Java/Extensions for individual users.) Or add BeanShell to your classpath like this: unix: export CLASSPATH=$CLASSPATH:bsh-xx.jar windows: set classpath %classpath%;bsh-xx.jar |
| Tip: You can modify the classpath from within BeanShell using the addClassPath() and setClassPath() commands. |
java bsh.Console // run the graphical desktop
or
java bsh.Interpreter // run as text-only on the command line
or
java bsh.Interpreter filename [ args ] // run script file
|
foo = "Foo";
four = (2 + 2)*2/2;
print( foo + " = " + four ); // print() is a BeanShell command
// Do a loop
for (i=0; i<5; i++)
print(i);
// Pop up a frame with a button in it
button = new JButton( "My Button" );
frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);
|
| Tip: BeanShell commands are not really "built-in" but are simply BeanShell scripts that are automatically loaded from the classpath. You can add your own scripts to the classpath to extend the basic command set. |
int addTwoNumbers( int a, int b ) {
return a + b;
}
sum = addTwoNumbers( 5, 7 ); // 12
|
add( a, b ) {
return a + b;
}
foo = add(1, 2); // 3
foo = add("Oh", " baby"); // "Oh baby"
|
ActionListener scriptedListener = new ActionListener() {
actionPerformed( event ) { ... }
}
|
ml = new MouseListener() {
mousePressed( event ) { ... }
// handle the rest
invoke( name, args ) { print("Method: "+name+" invoked!");
}
|
foo() {
print("foo");
x=5;
bar() {
print("bar");
}
return this;
}
myfoo = foo(); // prints "foo"
print( myfoo.x ); // prints "5"
myfoo.bar(); // prints "bar"
|
import bsh.Interpreter;
Interpreter i = new Interpreter(); // Construct an interpreter
i.set("foo", 5); // Set variables
i.set("date", new Date() );
Date date = (Date)i.get("date"); // retrieve a variable
// Eval a statement and get the result
i.eval("bar = foo*10");
System.out.println( i.get("bar") );
// Source an external script file
i.source("somefile.bsh");
|
| Tip: In the above example the Interpreter's eval() method also returned the value of bar as the result of the evaluation. |
/*
Standard Java syntax
*/
// Use a hashtable
Hashtable hashtable = new Hashtable();
Date date = new Date();
hashtable.put( "today", date );
// Print the current clock value
print( System.currentTimeMillis() );
// Loop
for (int i=0; i<5; i++)
print(i);
// Pop up a frame with a button in it
JButton button = new JButton( "My Button" );
JFrame frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);
|
/*
Loosely Typed Java syntax
*/
// Use a hashtable
hashtable = new Hashtable();
date = new Date();
hashtable.put( "today", date );
// Print the current clock value
print( System.currentTimeMillis() );
// Loop
for (i=0; i<5; i++)
print(i);
// Pop up a frame with a button in it
button = new JButton( "My Button" );
frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);
|
try {
int i = 1/0;
} catch ( ArithmeticException e ) {
print( e );
}
|
try {
...
} catch ( e ) {
print( "caught exception: "+e );
}
|
| Note: As of BeanShell version 1.3 the default scoping of loosely typed variables was changed to be more consistent with Java. BeanShell still supports an alternate scoping used in earlier versions. This mode can be enabled for legacy code by setting the system property "localscoping" to true. See appendix "Local Scoping". |
// Arbitrary code block
{
y = 2; // Untyped variable assigned
int x = 1; // Typed variable assigned
}
print( y ); // 2
print( x ); // Error! x is undefined.
// Same with any block statement: if, while, try/catch, etc.
if ( true ) {
y = 2; // Untyped variable assigned
int x = 1; // Typed variable assigned
}
print( y ); // 2
print( x ); // Error! x is undefined.
|
for( int i=0; i<10; i++ ) { // typed for-init variable
j=42;
}
print( i ); // Error! 'i' is undefined.
print( j ); // 42
for( z=0; z<10; z++ ) { } // untyped for-init variable
print( z ); // 10
|
button = new java.awt.Button();
button.label = "my button"; // Equivalent to: b.setLabel("my button");
print( button.label ); // Equivalent to print( b.getLabel() );
|
Float f = new Float(42f); print( f.infinite ); // Equivalent to print( f.isInfinite() ); // false |
b = new java.awt.Button();
b{"label"} = "my button"; // Equivalent to: b.setLabel("my button");
h = new Hashtable();
h{"foo"} = "bar"; // Equivalent to: h.put("foo", "bar");
|
List foo = getSomeList();
for ( untypedElement : foo )
print( untypedElement );
for ( Object typedElement: foo )
print( typedElement );
int [] array = new int [] { 1, 2, 3 };
for( i : array )
print(i);
for( char c : "a string" )
print( c );
|
dateobj = new Date();
switch( dateobj )
{
case newYears:
break;
case christmas:
break;
default:
}
|
int i=5; Integer iw = new Integer(5); print( i * iw ); // 25 Vector v = new Vector(); v.put(1); int x = v.getFirstElement(); |
// Standard Java import javax.xml.parsers.*; import mypackage.MyClass; |
import *; |
| Tip: The BeanShell which() command will use the classpath mapping capability to tell you where exactly in your classpath a specified class is located: bsh % which( java.lang.String ); Jar: file:/usr/java/j2sdk1.4.0/jre/lib/rt.jar |
importCommands("/bsh/commands");
|
| Tip: The classes java.awt.List and java.util.List are both imported by default. Because java.util.List is imported later, as part of the java.util package, it takes precedence. To access java.awt.List simply import it in, or the java.awt package again your script. Later imports take precedence. |
| @gt | > |
| @lt | < |
| @lteq | <= |
| @gteq | >= |
| @or | || |
| @and | && |
| @bitwise_and | & |
| @bitwise_or | | |
| @left_shift | << |
| @right_shift | >> |
| @right_unsigned_shift | >>> |
| @and_assign | &= |
| @or_assign | |= |
| @left_shift_assign | <<= |
| @right_shift_assign | >>= |
| @right_unsigned_shift_assign | >>>= |
int addTwoNumbers( int a, int b ) {
return a + b;
}
|
sum = addTwoNumbers( 5, 7 ); |
add( a, b ) {
return a + b;
}
|
foo = add(1, 2);
print( foo ); // 3
foo = add("Oh", " baby");
print( foo ); // Oh baby
|
// foo() and bar() are synchronized as if they were in a common class
synchronized foo() { }
synchronized bar() { }
|
a = 1;
anotherMethod() { ... }
foo() {
print( a );
a = a+1;
anotherMethod();
}
// invoke foo()
foo(); // prints 1
print( a ); // prints 2
|
a = 1;
foo() {
a = a + 1; // a is defined in parent scope
b = 3; // undefined, defaults local scope
int c = 4; // declared local scope
}
// invoke foo()
print( a ); // prints 2
print( b ); // ERROR! b undefined
print( c ); // ERROR! c undefined
|
foo() {
var a = 1;
}
foo();
print( a ); // ERROR! a is undefined!
|
foo() {
this.a = 1;
}
foo();
print( a ); // ERROR! a is undefined!
|
int a = 42;
foo() {
int a = 97;
print( a );
print( super.a );
}
foo(); // prints 97, 42
|
| Note: In standard Java, a method inside of an object (an instance method) may refer to the enclosing object using the special variable 'this'. For example:
// MyClass.java
MyClass {
Object getObject() {
return this; // return a reference to our object
}
}
In the example above, the getObject() method of MyClass returns a reference
to its own object instance (an instance of the MyClass object) using 'this'.
|
// Define the foo() method:
foo() {
int bar = 42;
print( bar );
}
// Invoke the foo() method:
foo(); // prints 42
print( bar ); // Error, bar is undefined here
|
foo() {
int bar = 42;
return this;
}
fooObject = foo();
print( fooObject.bar ); // prints 42!
|
foo() {
bar() {
...
}
}
|
foo() {
int a = 42;
bar() {
print("The bar is open!");
}
bar();
return this;
}
// Construct the foo object
fooObject = foo(); // prints "the bar is open!"
// Print a variable of the foo object
print ( fooObject.a ) // 42
// Invoke a method on the foo object
fooObject.bar(); // prints "the bar is open!"
|
foo() {
bar() { }
if ( true ) {
bar2() { }
}
return this;
}
|
| Note: If you print a 'this' type reference you'll see what it refers to:
BeanShell 1.3 - by Pat Niemeyer (pat@pat.net)
bsh % print( this );
'this' reference (XThis) to Bsh object: global
bsh % foo() { print(this); print(super); }
bsh % foo();
'this' reference (XThis) to Bsh object: foo
'this' reference (XThis) to Bsh object: global
|
global.foo = 42; |
// Create a top level object to hold some state
dataholder = object();
foo() {
...
bar() {
dataholder.value = 42;
}
bar();
print( dataholder.value );
}
|
| Tip: In the above example we used the BeanShell object() command to create an "empty" BeanShell scripted object context in which to hold some data. The object() command is just a standard empty method named object() that returns 'this'. The variable 'dataholder' above is a 'this' type reference and has all of the properties of any other BeanShell object scope. |
print( this ); // 'this' reference (XThis) to Bsh object: global
// The following cases all synchronize on the same lock
synchronized ( this ) { } // synchronized block
synchronized int foo () { } // synchronized method foo()
synchronized int bar () { } // synchronized method bar()
int gee() {
synchronized( super ) { } // synchronized blockinside gee()
}
|
buttonHandler = new ActionListener() {
actionPerformed( event ) {
print(event);
}
};
button = new JButton();
button.addActionListener( buttonHandler );
frame(button);
|
ActionListener interface and assigned it to a variable called
buttonHandler.
The buttonHandler object contains the scripted method actionPerformed(),
which will be called to handle invocations of that method on the interface.
Note that in the example we registered our scripted ActionListener with a
JButton using its addActionListener() method. The JButton is, of course,
a standard Swing component written in Java. It has no knowledge that when it
invokes the buttonHandler's actionPerformed() method it will actually be
causing the BeanShell interpreter to run a script to evaluate the outcome.
To generalize beyond this example a bit - Scripted interfaces work by looking
for scripted methods to implement the methods of the interface.
A Java method invocation on a script that implements an interface causes
BeanShell to look for a corresponding scripted method with
a matching signature (name and argument types). BeanShell then invokes the
method, passing along the arguments and passing back any return value.
When BeanShell runs in the same Java VM as the rest of the code, you can
freely pass "live" Java objects as arguments and return values, working
with them dynamically in your scripts; the integration can be seamless.
See also the dragText example.
actionPerformed( event ) {
print( event );
}
button = new JButton("Foo!");
button.addActionListener( this );
frame( button );
|
ActionEvents are fired by the button, your
actionPerformed() method will be invoked. The BeanShell 'this' reference
to our script implements the interface and directs method invocations to the
appropriately named method, if it exists.
| Note: If you want to have some fun, try entering the previous example interactively in a shell or on the command line. You'll see that you can then redefine actionPerformed() as often as you like by simply entering the method again. Each button press will find the current version in your shell. In a sense, you are working inside a dynamic Java object that you are creating and modifying as you type. Neat, huh? Be the Bean! |
messageButton( message ) {
JButton button = new JButton("Press Me");
button.addActionListener( this );
JFrame frame = frame( button );
actionPerformed( e ) {
print( message );
frame.setVisible(false);
}
}
messageButton("Hey you!");
messageButton("Another message...");
|
actionPerformed( event ) {
print( event );
}
button.addActionListener(
(ActionListener)this ); // added cast
|
mouseHandler = new MouseListener() {
mousePressed( event ) {
print("mouse button pressed");
}
invoke( method, args ) {
print("Undefined method of MouseListener interface invoked:"
+ name +", with args: "+args
);
}
};
|
import javax.xml.parsers.*;
import org.xml.sax.InputSource;
factory = SAXParserFactory.newInstance();
saxParser = factory.newSAXParser();
parser = saxParser.getXMLReader();
parser.setContentHandler( this );
invoke( name, args ) {
print( name );
}
parser.parse( new InputSource(bsh.args[0]) );
|
| Tip: You can use the invoke( name, args ) meta-method directly in your own scope or in the global scope as well, in which case you can handle arbitrary "unknown" method invocations yourself, perhaps to implement your own "virtual" commands. Try typing this on the command line:
invoke(name,args) { print("Command: "+name+" invoked!"); }
noSuchMethod(); // prints "Command: noSuchMethod() invoked!"
|
foo() {
run() {
// do work...
}
return this;
}
foo = foo();
// Start two threads on foo.run()
new Thread( foo ).start();
new Thread( foo ).start();
|
| Note: You can use the bg() "background" command to run an external script in a separate thread. See bg(). |
| Note: The choice of "bsh" for the root system object name was somewhat unfortunate because it conflicts with the current package name for BeanShell (also bsh). This means that if you wish to work with BeanShell classes explicitly from BeanShell scripts (e.g. bsh.Interpreter) you must first import them, e.g.:
import bsh.Interpreter;
i=new Interpreter();
|
if ( foobar == void )
// undefined
|
a == void; // true
a=5;
unset("a"); // note the quotes
a == void; // true
|
getBshPrompt() { return bsh.cwd + " % "; }
|
| Tip: You can easily override any BeanShell command simply by defining the method yourself in your script. For example:
print( arg ) {
System.out.println( "You printed: " + arg );
}
If you define the method in the global scope it will apply everywhere. If you
define it local to a scripted object it will only apply in that object context.
|
| exit() | Exit the interpreter. (Also Control-D). |
| show() | Turn on "show" mode which prints the result of every evaluation that is not of void type. |
| setAccessibility() | Turn on access to private and protected members of Java classes. |
| server() | Launch the remote access mode, allowing remote access to the interpreter from a web browser or telnet client. |
| debug() | Turns on debug mode. Note: this is very verbose, unstructured output and is primarily of interest to developers. |
| setStrictJava() | Turn on "strict Java" mode which enforces Java compatibility by dissallowing loose types and undeclared variables. |
| print(), error() | Print output to standard out or standard error. print() always goes to the console, whereas System.out may or may not be captured by a GUI console or servlet. |
| frame() | Display the AWT or Swing component in a Frame |
| eval() | Evaluate a string as if it were typed in the current scope. |
| source(), sourceRelative() | Read an external script file into the interpreter and evaluate it in the current scope |
| run(), bg() | Run an external file in a subordinate interpreter or in a background thread in a subordinate interpreter. |
| exec() | Run a native executable in the host OS |
| javap() | Print the methods and fields of an object, similar to the output of javap |
| which() | Like the Unix 'which' command for executables. Map the classpath and determine the location of the specified class. |
| load(), save() | load a serializable object from a file or save one to a file. Special handling is provided for certain objects. |
| object() | Create an "empty" object context to hold variables; analogous to a Map. |
| clear() | Clear all variables, methods and imports from the current scope. |
| unset() | Remove a variable from the current scope. (Return it to the "undefined" state). |
| setNameSpace() | Set the current namespace to a specified scope. Effectively bind the current scope to a new parent scope. |
| addClassPath(), setClassPath(), getClassPath() | Modify the BeanShell classpath. |
| reloadClasses() | Reload a class or group of classes. |
| getClass() | Load a class explicitly taking into account the BeanShell classpath. |
| getResource() | Get a resource from the classpath. |
| cd(), pwd(), dir(), rm(), mv(), cat() | Unix Style file commands. |
| pathToFile() | Translate a relative path to an absolute path taking into account the BeanShell current working directory. |
| classBrowser(), browseClass() | Open a class browser window or browse a specific class or object. |
| desktop() | Launch the BeanShell GUI desktop. |
| setNameCompletion() | Turn on or off name completion in the GUI console. |
| Note: The dir() command is written in Java; primarily as a demonstration of how to do this when desired. |
// File: helloWorld.bsh
helloWorld() {
print("Hello World!");
}
|
addClassPath("/home/pat"); // If it's not already in our classpath
importCommands("/mycommands");
|
helloWorld(); // prints "Hello World!" |
// equivalent
importCommands("com.xyz.utils");
importCommands("/com/xyz/utils");
|
// File: helloWorld.bsh
helloWorld() {
print("Hello World!");
}
helloWorld( String msg ) {
print("Hello World: "+msg);
}
|
/**
Implement dir() command.
*/
public static void invoke( Interpreter env, CallStack callstack )
{
String dir = ".";
invoke( env, callstack, dir );
}
/**
Implement dir( String directory ) command.
*/
public static void invoke(
Interpreter env, CallStack callstack, String dir )
{
...
}
|
invoke( String methodName, Object [] arguments ) {
print("You invoked the method: "+ methodName );
}
// invoke() will be called to handle noSuchMethod()
noSuchMethod("foo");
|
| Note: Note that this means that currently scripted commands may only be loaded once and then they are effectively cached. |
fooSetter() {
this.caller.foo=42;
}
|
fooSetter(); print( foo ); // 42 |
foo() { ... }
foo();
|
foo() {
bar() { ... }
...
}
// somewhere
fooObject.bar();
|
The diagram above shows the foo() and bar() scopes, along with the caller's
scope access via 'this.caller'.
This is very useful in writing BeanShell commands.
BeanShell command methods are always loaded into the global
scope. If you refer to 'super' from your command you will simply
get 'global'. Often it is desirable to write commands that explicitly have
side effects in the caller's scope. The ability to do so makes it possible to
write new kinds of commands that have the appearance of being "built-in"
to the language.
A good example of this is the eval() BeanShell command. eval() evaluates
a string as if it were typed in the current context. To do this, it sends
the string to an instance of the BeanShell interpreter. But when it does
so it tells the interpreter to evaluate the string in a specific namespace:
the namespace of the caller; using this.caller.
eval("a=5");
print( a ); // 5
|
eval( String text ) {
this.interpreter.eval( text, this.caller.namespace );
}
|
this.caller.caller...;
|
myCommand() {
// "Step into" the caller's namespace.
setNameSpace( this.caller.namespace );
// work as if we were in the caller's namespace.
}
|
object = object(); // save our namespace savedNameSpace = this.namespace; // step into object's namespace setNameSpace( object.namespace ); // Work in the object's scope a=1; b=2; // step back setNameSpace( savedNameSpace ); print( object.a ); // 1 print( object.b ); // 2 print( a ); // ERROR! undefined |
assert( boolean condition )
{
if ( condition )
print( "Test Passed..." );
else {
print(
"Test FAILED: "
+"Line: "+ this.namespace.getInvocationLine()
+" : "+this.namespace.getInvocationText()
+" : while evaluating file: "+getSourceFileInfo()
);
super.test_failed = true;
}
}
|
absfilename = pathToFile( filename ); |
dir("c:/Windows"); // ok
dir("c:\\Windows"); // ok
|
javap( Date.class ); // use a class type directly javap( new Date() ); // uses class of object javap( "java.util.Date" ); // Uses string name of class javap( java.util.Date ); // Use plain class identifier |
import bsh.ClassIdentifier;
if ( o instanceof ClassIdentifier )
clas = this.namespace.identifierToClass(o);
if ( o instanceof String)
clas = this.namespace.getClass((String)o);
else if ( o instanceof Class )
clas = o;
else
clas = o.getClass();
|
cm = CollectionManager.getCollectionManager();
if ( cm.isBshIterable( myObject ) )
{
BshIterator iterator = cm.getBshIterator( myObject );
while ( iterator.hasNext() )
i = iterator.next();
}
|
setStrictJava(true);
int a = 5;
foo=42; // Error! Undeclared variable 'foo'.
bar() { .. } // Error! No declared return type.
|
addClassPath( "/home/pat/java/classes" );
addClassPath( "/home/pat/java/mystuff.jar" );
addClassPath( new URL("http://myserver/~pat/somebeans.jar") );
|
cd("/tmp");
addClassPath("."); // /tmp
|
import *; |
reloadClasses(); |
reloadClasses("mypackage.*");
|
reloadClasses(".*")
reloadClasses("<unpackaged>")
|
reloadClasses("mypackage.MyClass")
|
name="foo.bar.MyClass"; c = getClass( name ); c = BshClassManager.classForName( name ); // equivalent |
java bsh.Interpreter [ filename ] [ arg ] [ ... ] // Run a script file |
// servlet mode URL java bsh.Remote http://localhost/bshservlet/eval test1.bsh // remote server mode URL java bsh.Remote bsh://localhost:1234/ test1.bsh |
| Tip: The BeanShell GUI is comprised mostly of a set of BeanShell scripts supplied in the JAR file and launched by the BeanShell desktop() command. |
java bsh.Interpreter // Run interactively on the command line |
| Tip: You can exit from an interactive shell by typing Control-D. |
| Unix | $HOME/.bshrc |
| Win95/98 single user | C:\Windows\.bshrc |
| Win98 Multiuser | C:\Windows\Profiles\<username>\.bshrc |
| NT/2K | C:\Winnt\Profiles\<username>\.bshrc |