/usr/share/doc/bsh-doc/html/interfaces.html is in bsh-doc 2.0b4-12build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | <?xml version="1.0" encoding="UTF-8"?>
<html><head><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"/>
<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/><center><table border="1" cellpadding="5" width="100%"><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 CLEAR="ALL"/>
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"/>
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"/>
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"/>
See also <a href="examples/dragtext.html">the dragText example</a>.
<p CLEAR="ALL"/>
<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"/>
For example, we could script an event handler for our button even
more simply using just a global method, like this:
<p/><center><table border="1" cellpadding="5" width="100%"><tr><td bgcolor="#dfdfdc"><pre>
actionPerformed( event ) {
print( event );
}
button = new JButton("Foo!");
button.addActionListener( this );
frame( button );
</pre></td></tr></table></center><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"/>
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/><center><table cellpadding="5" border="1" width="90%"><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/>
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/><center><table border="1" cellpadding="5" width="100%"><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/>
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"/>
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"/>
<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/><center><table border="1" cellpadding="5" width="100%"><tr><td bgcolor="#dfdfdc"><pre>
actionPerformed( event ) {
print( event );
}
button.addActionListener(
(ActionListener)this ); // added cast
</pre></td></tr></table></center><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"/>
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"/>
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"/>
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"/>
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"/>
<h2><a name=""Dummy"_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"/>
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"/>
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"/>
<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/><center><table border="1" cellpadding="5" width="100%"><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 CLEAR="ALL"/>
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"/>
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/><center><table border="1" cellpadding="5" width="100%"><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/>
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/><center><table cellpadding="5" border="1" width="100%"><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/>
<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/><center><table border="1" cellpadding="5" width="100%"><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 CLEAR="ALL"/>
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/><center><table cellpadding="5" border="1" width="90%"><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 CLEAR="ALL"/>
<h2><a name="Limitations">Limitations</a></h2>
<p CLEAR="ALL"/>
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"/>
<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>
|