Sophie

Sophie

distrib > Mageia > 6 > armv5tl > by-pkgid > 9e9fbbefd2001d780f31040381fe729b > files > 38

bsh-manual-1.3.0-37.mga6.noarch.rpm

<html><head><META http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Scripting Interfaces</title></head><body bgcolor="ffffff"><table cellspacing="10"><tr><td align="center"><a href="http://www.beanshell.org/"><img src="../images/homebutton.gif"><br>Home</a></td><td><a href="scope.html#Scope_Modifiers"><img src="../images/backbutton.gif"><br>Back
			</a></td><td align="center"><a href="contents.html"><img src="../images/upbutton.gif"><br>Contents</a></td><td align="center"><a href="specialvarsvalues.html#Special_Variables_and_Values"><img src="../images/forwardbutton.gif"><br>Next
			</a></td></tr></table><h1>Scripting Interfaces</h1>


One of the most powerful features of BeanShell is the ability to script 
Java interfaces.  This feature allows you to write scripts that serve
as event handlers, listeners, and components of other Java APIs.  It also 
makes calling scripted components from within your applications easier
because they can be made to look just like any other Java object.
<p CLEAR="ALL"></p>

<h2><a name="Anonymous_Inner-Class_Style">Anonymous Inner-Class Style</a></h2>

One way to get a scripted component to implement a Java interface is by 
using the standard Java anonymous inner class syntax to construct a scripted 
object implementing the interface type.  For example:
<p CLEAR="ALL"></p>

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
buttonHandler = new ActionListener() {
    actionPerformed( event ) { 
        print(event);
    }
};

button = new JButton();
button.addActionListener( buttonHandler );
frame(button);
</pre></td></tr></table></center><p></p>
<p CLEAR="ALL"></p>

In the above example we have created an object that implements the 
<code>ActionListener</code> 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.
<p CLEAR="ALL"></p>

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.
<p CLEAR="ALL"></p>

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.
<p CLEAR="ALL"></p>

See also <a href="examples/dragtext.html">the dragText example</a>.
<p CLEAR="ALL"></p>

<h2><a name="'this'_references_as_Interface_Types">'this' references as Interface Types</a></h2>

The anonymous inner class style syntax which we just discussed allows you
to explicitly create an object of a specified interface type, just as you
would in Java.  But BeanShell is more flexible than that.  In fact, 
within your BeanShell scripts, any 'this' type script reference can
automatically implement any interface type, as needed.  This means that you can 
simply use a 'this' reference to your script or a scripted object anywhere
that you would use the interface type.  BeanShell will automatically "cast" 
it to the correct type and perform the method delegation for you. 
<p CLEAR="ALL"></p>

For example, we could script an event handler for our button even
more simply using just a global method, like this:

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
actionPerformed( event ) {
    print( event );
}

button = new JButton("Foo!");
button.addActionListener( this );
frame( button ); 
</pre></td></tr></table></center><p></p>

Here, instead of making a scripted object to hold our actionPerformed()
method we have simply placed the method in the current context 
(the global scope) and told BeanShell to look there for the method.
<p CLEAR="ALL"></p>

Just as before, when <code>ActionEvents</code> 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.
<p CLEAR="ALL"></p>

<p></p><center><table width="90%" border="1" cellpadding="5"><tr><td bgcolor="#eeeebb"><strong>Note:</strong><br CLEAR="ALL">
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!
</td></tr></table></center><p></p>

Of course, you don't have to define all of your interface methods globally.
You can create references in any scope, as we discussed in "Scripting Objects".
For example, the following code creates a scripted message button object which
displays a message when its pushed.  The scripted object holds its own
actionPerformed() method, along with a variable to hold the Frame used for 
the GUI:
<p CLEAR="ALL"></p>

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
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...");
</pre></td></tr></table></center><p></p>

The above example creates two buttons, with separate messages.  Each button
prints its message when pushed and then dismisses itself.  
The buttons are created by separate calls to the messageButton() method,
so each will have its own method context, separate local variables, and a 
separate instance of the ActionListener interface handler.  Each registers 
itself (its own method context) as the ActionListener for its button, using 
its own 'this' reference.
<p CLEAR="ALL"></p>

In this example all of the "action" is contained in messageButton() method
context.  It serves as a scripted object that implements the interface and
also holds some state, the frame variable, which is used to dismiss the GUI.
More generally however, as we saw in the "Scripting Objects" section,
we could have returned the 'this' reference to the caller, allowing it to 
work with our messageButton object in other ways.
<p CLEAR="ALL"></p>

<h2><a name="Interface_Types_and_Casting">Interface Types and Casting</a></h2>

It is legal, but not usually necessary to perform an explicit cast of a 
BeanShell scripted object to an interface type.   For example:

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
actionPerformed( event ) {
    print( event );
}

button.addActionListener( 
    (ActionListener)this ); // added cast
</pre></td></tr></table></center><p></p>

In the above, the cast to ActionListener would have been done automatically
by BeanShell when it tried to match the 'this' type argument to the signature
of the addActionListener() method.
<p CLEAR="ALL"></p>

Doing the cast explicitly has the same effect, but takes a different route
internally.  With the cast, BeanShell creates the necessary adapter 
that implements the ActionListener interface first, at the time of the cast,
and then later finds that the method is a perfect match.  
<p CLEAR="ALL"></p>

What's the difference?  Well, there are times where performing
an explicit cast to control when the type is created may be important. 
Specifically, when you are passing references out of your script, to Java 
classes that don't immediately use them as their intended type.

In our earlier discussion we said that automatic casting happens "within
your BeanShell scripts".  And in our examples so far BeanShell has always
had the opportunity to arrange for the scripted object to become the correct
type, before passing it on.  But it is possible for you to pass a 'this'
reference to a method that, for example, takes the type 'Object', in which
case BeanShell would have no way of knowning what it was destined for later.
You might do this, for example, if you were placing your scripted objects
into a collection (Map or List) of some kind.  In that case, you can 
control the process by performing an explicit cast to the desired type before 
the reference leaves your script.
<p CLEAR="ALL"></p>

Another case where you may have to perform a cast is where you are using
BeanShell in an embedded application and returning a scripted object as
the result of an eval() or a get() variable from the Interpreter class.  
There again
is a case where BeanShell has no way of knowing the intended type within
the script.   By performing an explicit cast you can create the type
before the reference leaves your script.
<p CLEAR="ALL"></p>
We'll discuss embedded applications of BeanShell in the
"Embedding BeanShell" section a bit later, along with the Interpreter 
getInterface() method, which is another way of accomplishing this type of
cast from outside a script.
<p CLEAR="ALL"></p>

<h2><a name="&quot;Dummy&quot;_Adapters_and_Incomplete_Interfaces">"Dummy" Adapters and Incomplete Interfaces</a></h2>

It is common in Java to see "dummy" adapters created for interfaces that
have more than one method.  The job of a dummy adapter is to implement all
of the methods of the interface with stubs (empty bodies), allowing the
developer to extend the adapter and override just the methods of interest.
<p CLEAR="ALL"></p>

We hinted in our earlier discussion that BeanShell could handle scripted
interfaces that implement only the subset of methods that are actually used 
and that is indeed the case.  You are free in BeanShell to script only the 
interface methods that you expect to be called.  The penalty for leaving out 
a method that is actually invoked is a special run-time exception: 
java.lang.reflect.UndeclaredThrowableException, which the caller will 
receive.  
<p CLEAR="ALL"></p>

The UndeclaredThrowableException is an artifact of Java Proxy API that makes
dynamic interfaces possible.  It says that an interface threw a checked
exception type that was not prescribed by the method signature.  This is 
a situation that cannot normally happen in compiled Java.  So the Java 
reflection API handles it by wrapping the checked exception in this special
unchecked (RuntimeException) type in order to throw it.  
You can get the underlying
error using the exception's getCause() method, which will, in this case, 
reveal the BeanShell EvalError exception, reporting that the scripted method 
of the correct signature was not found.
<p CLEAR="ALL"></p>


<h3>The invoke() Meta-Method</h3>

BeanShell provides a very simple short-hand mechanism for scripting interfaces
with large numbers of methods.  You can implement the special method 
<em>invoke( name, args )</em> in any scripted 
context.  The invoke() method will be called to handle the invocation of
any method of the interface that is not defined. For example:
<p CLEAR="ALL"></p>

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
mouseHandler = new MouseListener() {
    mousePressed( event ) { 
        print("mouse button pressed");  
    }

    invoke( method, args ) { 
        print("Undefined method of MouseListener interface invoked:"
            + name +", with args: "+args
        );
    }
};
</pre></td></tr></table></center><p></p>
<p CLEAR="ALL"></p>

In the above example we have neglected to implement four of the five 
methods of the MouseListener interface.  They will be handled by the invoke()
method, which will simply print the name of the method and its arguments.
However since mousePressed() is defined it will be called for the interface.
<p CLEAR="ALL"></p>

Here is a slightly more realistic example of where this comes in handy.
Let's use the invoke() method to print the names of methods called via
the ContentHandler interface of the Java SAX API, while parsing an XML 
document.

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
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]) );
</pre></td></tr></table></center><p></p>

By running this script with the XML file as an argument, we can see which
of the dozen or so methods of the SAX API are being exercised by the structure 
of the document, without having to write a stub for each of them.
<p CLEAR="ALL"></p>

<p></p><center><table width="100%" border="1" cellpadding="5"><tr><td><strong>Tip:</strong><br CLEAR="ALL">
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:
<pre>
  invoke(name,args) { print("Command: "+name+" invoked!"); }
  noSuchMethod(); // prints "Command: noSuchMethod() invoked!"
</pre>
</td></tr></table></center><p></p>

<h2><a name="Threads_-_Scripting_Runnable">Threads - Scripting Runnable</a></h2>

BeanShell 'this' type references can implement the standard java.lang.Runnable 
interface.  So you can declare a "run()" method in your bsh objects and make 
it the target of a Thread:

<p></p><center><table width="100%" cellpadding="5" border="1"><tr><td bgcolor="#dfdfdc"><pre>
foo() {
    run() {
        // do work...
    }
    return this;
}

foo = foo();
// Start two threads on foo.run()
new Thread( foo ).start();
new Thread( foo ).start();
</pre></td></tr></table></center><p></p>
<p CLEAR="ALL"></p>

BeanShell is thread-safe internally, so as long as your scripts do not 
explicitly do anything ordinarily non-thread safe (e.g. access shared 
variables or objects) you can write multi-threaded scripts.
<p CLEAR="ALL"></p>

<p></p><center><table width="90%" border="1" cellpadding="5"><tr><td bgcolor="#eeeebb"><strong>Note:</strong><br CLEAR="ALL">
You can use the bg() "background" command to run an external script in a 
separate thread.  See bg().
</td></tr></table></center><p></p>
<p CLEAR="ALL"></p>

<h2><a name="Limitations">Limitations</a></h2>
<p CLEAR="ALL"></p>

When running under JDK 1.3 or greater BeanShell can script any kind of 
Java interface.  However when running under JDK 1.2 (or JDK1.1 + Swing) only 
the core AWT and Swing interfaces are available.  To support those legacy
cases a special extension of the 'this' reference implementation (the 
bsh.This class) is loaded which implements these interfaces along with 
Runnable, statically.  
<p CLEAR="ALL"></p>

<table cellspacing="10"><tr><td align="center"><a href="http://www.beanshell.org/"><img src="../images/homebutton.gif"><br>Home</a></td><td><a href="scope.html#Scope_Modifiers"><img src="../images/backbutton.gif"><br>Back
			</a></td><td align="center"><a href="contents.html"><img src="../images/upbutton.gif"><br>Contents</a></td><td align="center"><a href="specialvarsvalues.html#Special_Variables_and_Values"><img src="../images/forwardbutton.gif"><br>Next
			</a></td></tr></table></body></html>