5

Is it possible to reuse one and the same Nashorn engine and one and the same JavaScriptObject, which results as the evaluation of a JS-function, for all servlet requests, if the function does not change any shared object but uses only the arguments given with the call? Look at the following example:

public class MyServlet extends HttpServlet {

private ScriptEngineManager factory;
private ScriptEngine engine;
private ScriptObjectMirror script;

@Override
public void init() throws ServletException {
    try {
        factory = new ScriptEngineManager();
        engine = factory.getEngineByName("nashorn");
        script = (ScriptObjectMirror)engine.eval("function(writer) {writer.print('Hello, World!');}");
    } catch (ScriptException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        script.call(null, writer);
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Is this thread-safe? This is a follow-up to Reuse Nashorn ScriptEngine in Servlet

Edit: I'm not sure what difference this makes for the question at hand, but to focus on the more interesting question, under which circumstances a call to an evaluated js-function is thread save, I made all fields final now. So the code is:

public class MyServlet extends HttpServlet {

final private ScriptEngineManager factory;
final private ScriptEngine engine;
final private ScriptObjectMirror script;

public MyServlet() {
    factory = new ScriptEngineManager();
    engine = factory.getEngineByName("nashorn");
    ScriptObjectMirror _script = null;
    try {
        _script = (ScriptObjectMirror) engine.eval("function(writer) {writer.print('Hello, World!');}");
    } catch (ScriptException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    script = _script;
}

@Override
public void init() throws ServletException {
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        script.call(null, writer);
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}
Community
  • 1
  • 1
Gregor
  • 2,917
  • 5
  • 28
  • 50

1 Answers1

1

None of your instance variables are safely published, so that's a big "no" right there. Also none of the documentation says that the classes you use are thread safe, so without some further documentation saying differently you have to assume that they are not thread safe.

Answer: nope.

Community
  • 1
  • 1
markspace
  • 10,621
  • 3
  • 25
  • 39
  • Could you be more specific about the concurrency issues that you see? The init method of the servlet is not invoked concurrently. So there should be no problem with the Script Engine. The evaluated script itself might be invoked concurrently, but it does not refer to any shared resource. Why do you think this is problematic? – Gregor Jan 01 '15 at 20:41
  • This might be a better question for Stackoverflow's sister site, programmers.stackexchange.com. I'll mention briefly: there is certainly a shared resource in `doGet()`, it's the `script` variable. As for `init()`, can you point to any JEE documentation that says there's any synchronization between `init()` and `doGet()`? This is basic stuff, you really need to learn more about multithreading if you can't see these issues. – markspace Jan 02 '15 at 01:00
  • 1
    As I wrote: the script is invoked concurrently. It is shared. But shared variables are not necessarilly not thread safe. the script itself does not write to any shared resource, as the servlet request is per thread. So what I need is an answer to the question, what is involved in calling a js-script. The Nashorn documentation is silent about this. Regarding the init method, you can see that it is empty in my improved example above. – Gregor Jan 02 '15 at 08:03