Asdfasf

Thursday, February 28, 2013

Dynamic Java Code Execution at Runtime with BeanShell

BeanShell provides to execute code snippets at runtime without compiling and restarting JVM. This functionality enables us to execute custom operations at runtime. Lets consider following case: Admin user of our system wants to manipulate a system value at runtime and enters a configuration for that purpose. Lets say, parameter, which manipulation will be executed on, holds a string tokenized with pipe character and we wants to change its value by finding max part of tokenized values.

Here is how that operation can be implemented with pure java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.ferhat.beanshell.work;

import java.util.StringTokenizer;

public class ValueManipulatorByJava {
 public static String getMax(String input) {
  StringTokenizer tok = new StringTokenizer(input, "|");
  int max = 0;
  while (tok.hasMoreElements()) {
   int intval = Integer.parseInt((String) tok.nextElement());
   if (intval > max) {
    max = intval;
   }
  }
  return String.valueOf(max);
 }

 public static void main(String[] args){
  long start = System.currentTimeMillis();
  System.out.println("Result is :" + getMax("9|3|10|11|1|8"));
  
  System.out.println("Java evaluation took " + (System.currentTimeMillis() - start) + " msec");
 }
}

Now lets see if this operation shall be done at runtime with provided code snippet:

 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
package com.ferhat.beanshell.work;

import bsh.EvalError;
import bsh.Interpreter;

public class ValueManipulatorByBeanShell {
 
 public static String getMax(String input, String script) throws EvalError {
  Interpreter i = new Interpreter();
  i.set("input", input);

  Object output = i.eval(script);

  return (String) output;
 }

 public static void main(String[] args) throws EvalError {
  
  String script = "StringTokenizer tok = new StringTokenizer(input, \"|\");\n" + 
    "  int max = 0;\n" + 
    "  while (tok.hasMoreElements()) {\n" + 
    "   int intval = Integer.parseInt((String) tok.nextElement());\n" + 
    "   if (intval > max) {\n" + 
    "    max = intval;\n" + 
    "   }\n" + 
    "  }\n" + 
    "  return String.valueOf(max);\n" +  
    "";
  
  String input = "9|3|10|11|1|8";

  long start = System.currentTimeMillis();
  String output = getMax(input, script);
  System.out.println("Result is: " + output);
  System.out.println("BeanShell evaluation took " + (System.currentTimeMillis() - start) + " msec");
  
  start = System.currentTimeMillis();
  output = getMax(input, script);
  System.out.println("Result is: " + output);
  System.out.println("BeanShell evaluation took " + (System.currentTimeMillis() - start) + " msec");
  
  start = System.currentTimeMillis();
  output = getMax(input, script);
  System.out.println("Result is: " + output);
  System.out.println("BeanShell evaluation took " + (System.currentTimeMillis() - start) + " msec");
 }
}
As easy as much above. Here is output:


1
2
3
4
5
6
Result is: 11
BeanShell evaluation took 69 msec
Result is: 11
BeanShell evaluation took 8 msec
Result is: 11
BeanShell evaluation took 8 msec

Finally, i must say that altough first execution takes some time, succeeding executions takes faily short time. BeanShell provides us significant flexibility over processes at runtime.

No comments: