`
george.gu
  • 浏览: 70975 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Beanshell: how and where to use beanshell

阅读更多

 

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))"); 


beanshell will print:
3
Oh baby
12


Demo 2: loosely typed variable in blocks

loosely typed variables in blocks are available in global scope:
for(i=0;i<5;i++){
print(i);
}
print(i);
will output:
0
1
2
3
4
5

But following print will cause error:
for(int i=0;i<5;i++){
print(i);
}
print(i); // ERROR! because typed int "i" is only available inside for loop blocks.

Demo 3: loosely typed variables in method blocks

add(a, b) {

c=5;

return a + b;

}

print(c);//ERROR! because c is only available inside add method blocks even it is loosely types.

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 http://www.beanshell.org/images/embeddedmode.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()

In Beanshell script methods, we can use "return this" to get a XThis instance of current interpreter context class:
myfile.bsh:
myDisplayCustomize(){
displayPlainPage(BufferedReader in, PrintStream out) throws IOException {
String line;
while ((line = in.readLine()) != null) {
out.println(line);
}
}
return this;
}

 

Interpreter bsh = new Interpreter();

bsh.eval("myObj = myDisplayCustomize()");

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:

myDisplayCustomize(){
displayPlainPage(BufferedReader in, PrintStream out) throws IOException {
String line;
while ((line = in.readLine()) != null) {
out.println(line);
}
}
return (IDisplayLog)this;
}
Then you can get the java instance and use it as normal java Object instance:
IDisplayLog myObj = (IDisplayLog) bsh.eval("myObj = myDisplayCustomize()"); myObj.displayPlainPage(in, System.out);


Where and when to use beanshell in Project

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:

 

  1. some user defined global macro;
  2. some components change often and you pay more attention on String parameters parsing;
  3. your configuration or script need to call other Java clall API.
  4. ...

 

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:

 

  1. 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.
  2. Macros and Evaluation: it is also related to customized requirement. you can define global macro and evaluation with beanshell.
  3. 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>


 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics