Monday 30 December 2013

Tech Talk...JavaScript execution from within JVM

This tutorial describes how to execute JavaScript from within java using the Rhino provided JavaScript execution Engine.

About Rhino:

What is Rhino JavaScript Engine
Maven Repository for Rhino Jar

How to invoke a JavaScript from within java using Rhino:


public class JavaScriptInvoker {
    String myfn = ""
            + "function sayHello(inputStr, outputStr){"
            + " outputStr =  \"Hello\"+inputStr;"
            + "}";
    Function function;
    Context ctx;
    ScriptableObject scriptable;

   public void initJs(){
        ctx = Context.enter();
        ctx.setOptimizationLevel(9);
        scriptable = ctx.initStandardObjects();
        function = ctx.compileFunction(scriptable, myfn, "sayHello", 0, null);
   }

   public void invokeJs(){
      String outputStr;
      Object[] args = {"Neha", outputStr};
      function.call(ctx, scriptable, function, args);
      System.out.println(outputStr);
   }

    public static void main(String[] args) throws Exception{
       JavaScriptInvoker jsInvoker = new JavaScriptInvoker();
       jsInvoker.initJs();
       jsInvoker.invokeJs();
    }
}


Understanding different parts of the program:

1. Initializing the JavaScript engine.
The Rhino JavaScript engine needs to be initialized before it can be used to invoke a java script. This initialization involves initializing the internal objects used by the JavaScript Engine (being done using the line  scriptable = ctx.initStandardObjects(); ) .This single line would be sufficient for you in most of the cases( unless you need to do some sophisticated initializations on your own.).
Also, an optimization level can be set on the context of the engine, which ensures how performant the invocation of JavaScript from within java will be (see the line:ctx.setOptimizationLevel(9);) Optimization levels are integers, 9 being the highest.
Finally, the javascript which has to be invoked, needs to be initialized. This is being done in the line:
 function = ctx.compileFunction(_scriptable, myfn, "sayHello", 0, null);

2. Invoking the JavaScript from within java at runtime.
Once the javascript engine is initialized, it can be invoked at runtime multiple times to invoke the function compiled above, that is happening in the code :
 function.call(ctx, scriptable, function, args);
The first two arguments to the call method are context object and scriptable object of the JavaScriptEngine to let it know of the initialization parameters.
The next parameter is the compiled function that needs to be called.
The final parameter is an Object array consisting of parameters being passed to the function being invoked.

3. Parameter passing / Object sharing between JavaScript and Java.
As seen in the code above, I am passing two parameters to the method sayHello : one input string and one output string. Both these are Java String Object types. They are successfully binded and passed to the function sayHello, which appends "Hello" to the input string and then assigns the result to output string and returns the output string back. On obtaining the output string, the java runtime can successfully use it for further operation.

4. Java method invocation from within javascript engine
From within the javascript function, any of the Java methods can be invoked, even objects can be passed from the java code to the javascript as initialization parameters or arguments and then they can be used by the javascript in any way possible.

No comments:

Post a Comment