BeanShell User's Guide

Introduction

This guide explains how to use the BeanShell Java interpreter with the Java Development Environment for Emacs. This guide contains the following sections:
 
 
About the BeanShell  Brief overview of the BeanShell 
Using the BeanShell  Explains how to start and shut down the BeanShell, enter statements, and show results.
The BeanShell Language  Describes the Java constructs and scripting extensions supported by the BeanShell
BeanShell Commands  Describes the commands supported by the BeanShell
 

About the BeanShell

The BeanShell is a Java interpreter that evaluates Java statements directly (without first compiling them). The  BeanShell has been included in the JDE with the permission of its author,  Pat Niemeyer.

The BeanShell can operate as a stand-alone application or as a part of another application. When running as a stand-alone application, the interpreter accepts input from the command line of the shell in which it runs. The BeanShell distribution includes a shell for running the interpreter. It can, however, be run from other shells, such as bash or the DOS command window. The JDE includes a command for running the BeanShell in an Emacs shell (comint) buffer. This enables you to interact with the interpreter directly while developing Java programs.

The JDE also  uses the interpreter to implement some JDE commands. The JDE invokes the interpreter via Lisp functions that pass Java statements to the interpreter via the standard input of the interpreter process and retrieve results via the standard output. This guide documents BeanShell functionality that seems relevant to JDE users.  See the BeanShell home page home page for additional information and to download the latest version of the BeanShell.

Using the BeanShell

Starting the BeanShell

To start the BeanShell, select Interpret from the JDE menu or enter the command M-x bsh. Emacs starts the BeanShell, if not already started, and displays its prompt in an Emacs shell buffer window.

The JDE allows you to run only one instance of the BeanShell at a time. If  an instance is already running, the bsh command simply displays the buffer containing the instance, without starting another instance. Note that you can indirectly start a BeanShell instance when you invoke commands implemented as hybrid Lisp/Java scripts, such as jde-wiz-override-method. Such commands start a BeanShell instance if one is not already running.

Evaluating Statements

To evaluate a Java statement, type it at the BeanShell prompt and press the Enter key. The BeanShell evaluates the statement. When it is done, it redisplays the the BeanShell command prompt. You can then enter another statement.

Statements must conform to Java syntax. For example, simple statements must end in a semicolon. Compound statements, such as if-then constructs, must end in a right brace. Statements may span multiple lines. To continue a statement on a new line, press the Enter key. The BeanShell does not evaluate the statement until you have entered the last line of the statement.


 

Displaying Results

You can display the results of evaluating Java statements via the BeanShell print and show commands. The print command accepts any Java expression as an argument and displays the result of evaluating that expression  in the BeanShell window. For example,
print(2+2);
displays
4
in the BeanShell window. Note that print(expr) is equivalent to System.out.println(expr) and you can use either method to print a Java expression.

The show(); command toggles automatic display of the results of evaluating statements as they are entered.

Exiting the Shell

To exit the BeanShell, enter
exit();
at the commmand prompt.

The BeanShell Language

Java Language Support

The BeanShell language includes most of the constructs of the Java language. Standard Java constructs supported by the BeanShell include  variable assignments, method calls, math expressions, for-loops, etc.. Here are some examples:
    // Use a hashtable

    Hashtable h = new Hashtable();

    Date d = new Date();

    h.put("today", d);



    // Print the current clock value

    print( System.currentTimeMillis() );



    // Loop

    for (int i=0; i<5; i++)

        print(i);



    // Pop up an AWT frame with a button in it

    Button b = new Button("My Button");

    Frame f = new Frame("My Frame");

    f.add(b, "Center");

    f.pack();

    f.show();
By default, the BeanShell imports the Java core classes at startup. You can import additional classes, using standard Java import syntax, for example,
import mypackage.*;
or
    import mypackage.MyClass;

Scripting Extensions

The BeanShell defines a number of extensions to the Java language designed to facilitate creation of scripts.  The scripting extensions include

Script Variables

The BeanShell allows you to create a special type of variable named a script variable. Unlike a standard Java variable, which can reference objects only of a specified type, a script variable can be defined to reference any type of object, including primitive types, such as int and boolean. You create a script variable by declaring it with or without a type specifier. If you include a type specifier, the variable can reference only values of the specified type. If you do not specify a type, the variable can reference values of any type. For example, the following statement
    foo = new Button("Another Button");
creates an untyped script variable named foo and assigns it a Button object. You are  free to subsequently assign foo to any other type of object.

Predefined Variables

Undefined variables

You can test to see if a variable is "undefined" with the value void, e.g.:
    if ( foobar == void )

        // undefined
You can return a defined variable to the undefined state using the unset() command:
a == void;  // true
a=5;
unset("a"); // note the quotes
a == void;  // true

Script Methods

BeanShell lets you define and use a special type of method called a script method. Script methods differ from standard Java methods in the following ways: You use standard Java syntax to declare a script  method that accepts and returns specific types. For example, the following code
    int addTwoNumbers( int a, int b ) {

        return a + b;

    }
defines a BeanShell method called addTwoNumbers that accepts and returns values of type int. The next example
    int a = addTwoNumbers( 5, 7 );
uses the newly defined method to add two values of type int.

You define an untyped script method by omitting type specifications. For example, the following statement

    add( a, b ) {

        return a + b;

    }
defines a script method that accepts arguments of any type. When you invoke an untyped script method, BeanShell interprets the method based on the types of the arguments that you pass to the method. Consider, for example, the following invocations of the untyped add method defined in the preceding example:
    foo = add(1, 2);

    print( foo ); // 3



    foo = add("Oh", " baby");

    print( foo ); // Oh baby
The first invocation returns the result of adding, the second, of concatenating the arguments.

Methods with unspecified return types may return any type of object or no object. A return statement is optional. If omitted, the method returns the value of the last statement or expression in the method body.

Method Namespace

The namespaces of script methods and variables are separate. Thus, you can define a method and a variable having the same name.

Nested Methods

Script methods may define methods, for example,
    foo() {

        bar() {

            ...

        }

    }
Method may be nested in this way to an arbitrary depth. Within a nested method, locally declared variables and methods  shadow identically named variables and methods declared in outer methods. Otherwise, variables and methods are visible to an arbitrary depth of scope. Outer methods can invoke methods defined by inner methods that return a this object, for example,

Implicit Objects

The methods and variables defined by a script method are considered to be methods and fields of an implicit object. The reserved identifiers, this, super, and global, refer, respectively, to the current object, the calling object, and the global object. A method can access any variable or method in these scopes by qualifying the variable's name with the name of the appropriate implicit object.
    a = 42;

    foo() {

        a = 97;

        print( a );

        print( this.a );

        print( super.a );

    }



    foo();  // prints 97, 97, 42
A script method can return its implicit object, thereby allowing the invoking script to access variables and methods defined by the method, using standard Java  "." notation. For example,
    foo() {

        int a = 42;

        bar() {

            print("The bar is open!");

        }

        

        bar();

        return this;

    }



    obj = foo();     // prints "the bar is open!"

    print ( obj.a )  // 42

    obj.bar();       // prints "the bar is open!"

Using Implicit Objects as AWT Event Handlers

Implicit method objects can serve as AWT event handlers. To handle an AWT event, a script method defines the appropriate event-handling method and then registering its implicit (this) object with the object in which the event originates. For example, the following script
    button = new java.awt.Button("foo!");



    actionPerformed( event ) {

        print( event );

    }



    button.addActionListener( this );

    frame( button );  // show it
defines an Action event handler and registers it with a button.

Remember that you don't have to define all of your event handlers globally. You can handle events in any bsh object scope. For example, the following method creates a button that displays a message when pushed:

    messageButton( message ) {

        b = new Button("Press Me");

        b.addActionListener( this );

        frame(b);

     

        actionPerformed( e ) {

            print( message );

        }

    }



    messageButton("Hey you!");

    messageButton("Another message...");
The above will create two buttons and each will display its own message when pushed. Each has a separate instance of the event handler object. Note too that we could return a 'this' reference from the handler method and use it in other contexts to register listeners...

Using Implicit Objects as Threads

'This' type references also implement the standard Runnable interface, so you can declare a "run()" method in your objects:
    foo() {
        run() {
            // do work...
        }
        return this;

    }
 
    foo = foo();
    new Thread( foo ).start();
 

Implicit Object Members

Implicit objects have four "magic" members:
  • this.interpreter refers to the currently executing BeanShell Interpreter object.
  • this.namespace refers to the BeanShell NameSpace object of the current context.
  • this.variables refers to an array of strings listing the variables defined in this namespace.
  • this.methods refers to an array of strings listing the methods defined in this namespace.
  • These are mainly for internal use by BeanShell commands. Note that there are certain special situations in which the this.interpreter reference may not be available, such as in AWT event handlers.

    Extended Syntax for Accessing Bean Properties and Hashtables Entries

    You may use the following syntax
    x{name}
    to access properties of Java beans and Hashtable entries, where x is a bean or Hashtable and name is a String that identifies a bean property or hashtable entry, for example:
        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");

    BeanShell Commands

    The BeanShell provides a set of commands for displaying data, invoking system utilities, and performing various other tasks. See the BeanShell Command Reference for a description of the syntax and usage of each command. The current crop of bsh commands follow. These are, for the most part, just very short bsh scripts, supplied in the bsh.jar file. See making bsh commands below for more details on adding to the "built-in" bsh command set.
     

    bg

    bg( String script )

    This is like run() except that it runs the command in its own thread. Returns the thread object (for stop()ing, join()ing, etc.)


    browseClass

    void browseClass(String classname);

    Displays a class browser. The browser enables you to browse the contents of any packages packaged as jar files on the classpath defined by jde-global-classpath.
     


    cat

    void cat( String filename )

    Print the contents of filename (like Unix cat)


    cd

    void cd(String dirname);

    Change working directory for the dir() command (like Unix cd).
     


    console

    bsh.Console console()

    Create a console window attached to the current interpreter. Returns the console Frame.


    dir

    void dir(String dirname)

    Display the contets of directory dirname. The format is similar to the Unix ls -l command.


    debug

    void debug()

    Toggle on and off debug mode... Note: debug output is verbose and gross.


    editor

    Frame Frame editor();

    Create an editor window with an "eval" button. This is primarily useful for typing multi-line commands and experimenting with methods when running the BeanShell outside of the Emacs environment. Returns the editor Frame.


    eval

    void eval( String expression )

    Evaluate the string in the current interpreter (see source).


     exec

    exec(String process);

    Get the Java Runtime and start the external process, display any output.


    exit

    void exit()

    Call System.exit(0);


    frame

    Frame frame(Component component);

    Display the component, centered and packed, in a top level Frame. Returns the frame. Frame takes additional steps to handle the WindowClosing AWT event and dispose of the frame, so that you an close the window normally.


     getResource

    URL getResource( String path )

    The equivalent of calling getResource() on the interpreter class in the bsh package. Use absolute paths to get stuff in the classpath.


    load

    Object load( String filename )

    Load a serialized Java object from filename. Returns the object.


    pathToFile

    File pathToFile( String filename )

    Create a File object corresponding to the specified file path name, taking into account the bsh current working directory (bsh.cwd)


    print

    void print(item);

    Print the string value of the item. item may be of any type.


    pwd

    void pwd();

    Print the bsh working directory. This is the cwd obeyed by all the unix like bsh comands.


    rm

    void rm();

    Remove the file (like Unix rm)


    run

    run( String script )

    run() is like source() except that it runs the command in a new, subordinate and prune()'d namespace. So it's like "running" a command instead of "sourcing" it ;)


    save

    void save(Component component, String filename);

    Save a serializable Java object to filename.

    Since the AWT Button class happens to be serializable, we could test drive the save() command.

        save(foo, "myButton.ser");
    If we did save our button, we could revive it later with the load() command.
      bar = load("myButton.ser");
    frame(bar);

     server

    void server( int port )

    Create a Server Mode server attached to the current interpreter, listening on the specified port.


     setFont

    Font setFont( Component comp, int ptsize )

    Change the point size of the font on the specified component, to ptsize.


    show

    void show();

    Toggle on or off the display of the value of expressions evalauted on the command line. Show mode may be useful if you find yourself typing print() a lot.


    source

    void source( String filename )

    Read filename into the interpreter and evaluate it in the current namespace. Like Bourne Shell "." command.


    unset

    void unset(String name);

    "undefine" the variable specified by 'name' (So that it tests == void).
     

    Making BeanShell Commands

    Adding to the set of "prefab" commands supplied with bsh can be about as easy as writing any other bsh methods. You simply have to place your bsh scripts in a bsh/commands/ directory in the classpath (or inside the JAR file).