How to use beanshell
beanshell Manual:
http://www.beanshell.org/manual/bshmanual.html
"loosely typed" variables
You can simply omit the types of variables that you use (both primitives and objects).
Beanshell automatically converts them to properly type before execute any operations. BeanShell will only signal an error if you attempt to misuse the actual type of the variable.
Demo 1: loosely typed method signature
take one method for an example:
add(a, b) {
return a + b;
}
Interpreter bsh = new Interpreter();
bsh.eval("print(add(1,2))");
bsh.eval("print(add(\"Oh \",\"baby\"))");
bsh.eval("print(add(\"1\",2))");
Demo 2: loosely typed variable in blocks
Demo 3: loosely typed variables in method blocks
add(a, b) {
c=5;
return a + b;
}
Document Friendly Entities
BeanShell supports special overloaded text forms of all common operators to make it easier to embed BeanShell scripts inside other kinds of documents (e.g XML)
@gt | > |
@lt | < |
@lteq | <= |
@gteq | >= |
@or | || |
@and | && |
@bitwise_and | & |
...
It is very useful when containing beanshell inside XML.
Demo 1:
import bsh.Interpreter;
Interpreter i = new Interpreter(); // Construct an interpreter
i.eval("print(5>4)"); // it will output: true
i.eval("print(\"5>4\")"); // it will output: 5>4
i.eval("print(5@gt4)"); // it will output: true
i.eval("print(\"5@gt4\")"); // it will output: 5@gt4
Demo 2:
Inside XML, we can use the beanshell like following:
if(a @gt b) {
//...
}
Calling beanshell in Java Application
(Image from https://i-blog.csdnimg.cn/blog_migrate/8161c12561e77e146d00c299e3926915.gif)
First, you should add beanshell library into your application classes path. For the moment, it is bsh-1.3.0.jar.
Initial beanshell intercepter
import bsh.Interpreter;
Interpreter i = new Interpreter(); // Construct an interpreter
eval("script_String") to interpret script string
The Interprete eval() method accepts a script as a string and interprets it, optionally returning a result. The string can contain any normal BeanShell script text with any number of Java statements. The Interpreter maintains state over any number of eval() calls, so you can interpret statements individually or all together.
TIt is not necessary to add a trailing ";" semi-colon at the end of the evaluated string. BeanShell always adds one at the end of the string.
Demo 1:
i.eval("foo=\"Foo\""); // it will set a loostly typed varialbe foo with initial value "Foo".
Demo 2:
i.eval("for (i=0;i<5;i++) print(i);") // it will display: 0 1 2 3 4
is not same as:
i.eval("for (i=0;i<5;i++)")
i.eval("print(i);") // it will display: 5
Demo 3:
Eash script string inside eval() should be a entire operation. Follwoing invocation will cause error:
i.eval("for (i=0;i<5;i++) {")
i.eval("print(i);")
i.eval("}")
set(), get() to exchange variables with Interpreter
You can use set(String name, Object value) to set variables into beanshell interpreter.
For example, you have a beanshell script:
c = 5;
foo () {
c = a + b;
//print(c);
return c;
}
You can set a and b like following:
i.set("a", 1);
i.set("b", "2");
Then you can perform an operation by invoke eval():
i.eval("foo()");
Now you can get value of c by invoke get():
i.get("c"); // you will get "12".
unset() and clear() command to eraser variables in current scope
unset(variable) used to remove a variable from the current scope. (Return it to the "undefined" state).
clear() used to Clear all variables, methods and imports from the current scope. It is not embedded in Interpreter class for the moment.
source() to read script from external file
The Interpreter source() method can be used to read a script from an external file:
i.source("/opt/tmp/mybeanshell.bsh");
source("beanshell script file") will read and interprete specified beanshell script file. You can use it to valid and test your beanshell script.
Import referenced classes
It is very important to import classes that will be referenced inside beanshell script. By default, beanshell interpreter import common Java core and extension packages for us. They are, in the order in which they are imported:
- javax.swing.event
- javax.swing
- java.awt.event
- java.awt
- java.net
- java.util
- java.io
- java.lang
Two BeanShell package classes are also imported by default:
- bsh.EvalError
- bsh.Interpreter
You can define classes import in bean shell scipt:
import com.gemalto.wgu.*;
Alternatively, you can also import classes through eval():
i.eval("import com.gemalto.wgu.*");
Scripted Objects, Methods and Interfaces
Here I would like to list four different approaches on how to invoke script in Java Application.
1-->No method definition: Beanshell file content = the body of your function method
Write your function in beanshell script file as global definition without define special method, in this case, your function code will be loaded and executed when interpreter source scripting file.
myfile.bsh:
c = 5 + 6;
print(c);
Interpreter.source("myfile.bsh"); // it will execute "c= 5 + 6" and print "11" directly.
2--> Script Methods and eval(): define your function in script method and call it in your application through eval()
Define your function inside a methods, then invoke method by eval(). If there are some other parameters, you can set("parametername", object_instance ) them.
myfile.bsh:
displayPlainPage(BufferedReader in, PrintStream out) throws IOException { String line; while ((line = in.readLine()) != null) { out.println(line); } }
Interpreter bsh = new Interpreter();
bsh.source("myfile.bsh");
bsh.set("in", BufferedReader Instance);
bsh.set("out", PrintStream Instance);
bsh.eval("displayPlainPage(in, out)"); // it will execute your function code.
Please be note: eval() will return result in "Object" instance to java context.
3--> Script Object and eval()
Interpreter bsh = new Interpreter();
bsh.eval("myObj.displayPlainPage(in, out)");
4--> Implement Interface and return Interface instance in script methods
You can define any java interface for your function:
public inteface IDisplayLog{
public void displayPlainPage(BufferedReader in, PrintStream out) throws IOException;
}
Then write a script method implement this API and return the object instance with explicity cast:
myfile.bsh:
Thanks to its lightly, no need compile, compliant with Java and loosely typed variables (which will be automatically gurranted by beanshell), you can use beanshell to make your application really flexible.
When your application meets one or some of following factors:
- some user defined global macro;
- some components change often and you pay more attention on String parameters parsing;
- your configuration or script need to call other Java clall API.
- ...
Please try beanshell to see if it can solve your issue and save time.
From beanshell manual: http://www.beanshell.org/manual/embeddedmode.html, you can see some general advice on when to use beanshell:
- Highly customized application or your application under intense change. What's more. if some component is really change often and is based on customer business rule, you can try to encapsulate thise part with beanshell.
- Macros and Evaluation: it is also related to customized requirement. you can define global macro and evaluation with beanshell.
- Simplify configuration file: you can define configuration file with beanshell script partition or entire.
In fact, some tools had already embedded beanshell support to provide flexible customized features.
For myself, I am using Jmeter and OsWorkflow engine. Both of them had embedded beanshell support. For example, we can use beanshell in workflow defintion:
<step id="2" name="XXX"> <actions> <action id="1001" name="Action 1" view="Action 1"> <pre-functions> <function type="beanshell" name="XXX"> <arg name="script"> import java.util.*; // Business logical in beanshell. transientVars.put("_simMenuTargetNode", SIMServiceTargetPath); </arg> </function> </pre-functions> <results> //... </results> </action> </actions> </step>