2014-01-27 23 views
1

我一直在努力解决使用java scripting API来控制某些用户定义的javascript的执行问题。我正在使用内置的Rhino引擎,它说你可以设置InstructionObserverThreshold,如果达到限制,它将负责停止执行。我一直在玩下面的示例应用程序一段时间,并且我为什么不起作用而难以接受。你会看到我已经设置了MaximumInterpreterStackDepth。这很好,但指导观察员似乎没有做任何事情。在javax.scripting环境中设置instructionObserverThreshold

有关此代码缺失的任何想法,使其工作?

谢谢!

import javax.script.ScriptEngine; 
import javax.script.ScriptEngineManager; 
import javax.script.ScriptException; 

import com.sun.script.javascript.RhinoScriptEngine; 


public class RhinoTester2 { 

    public static void main(String[] args) { 

    new RhinoScriptEngine(); // initialize the global context. 

    sun.org.mozilla.javascript.internal.ContextFactory cx = sun.org.mozilla.javascript.internal.ContextFactory.getGlobal(); 
    cx.addListener(new sun.org.mozilla.javascript.internal.ContextFactory.Listener() { 
     public void contextCreated(sun.org.mozilla.javascript.internal.Context cxt) { 
       cxt.setInstructionObserverThreshold(10000); // This should stop after 10 seconds or so. 
       cxt.setMaximumInterpreterStackDepth(1); // this should not be a factor for the moment 
       System.out.println("Context Factory threshold set. "+cxt.getInstructionObserverThreshold()); 
      } 

     @Override 
     public void contextReleased(
      sun.org.mozilla.javascript.internal.Context arg0) { 
      System.out.println("Context Released."); 
     } 

    }); 

     // Now run the script to see if it will be stopped after a short time. 
     ScriptEngineManager mgr = new ScriptEngineManager(); 
     ScriptEngine engine = mgr.getEngineByName("javascript"); 
     try { 
      // engine.eval("while(true){println(\"hello\");};"); // This will fail immediately due to the interpreter stack depth. 
      engine.eval("while(true){};"); // this never fails. runs happily forever. 
     } catch (ScriptException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 
+0

不幸的是,脚本API使用的基本ContextFactory中没有提供处理InstructionObservationCount的推荐方法。在查看RhinoScriptEngine时,用户无法修改ContextFactory以添加实现(密封类和匿名静态块调用initGlobal)。从我可以告诉你只有两个选项 - 要么创建自己的脚本引擎,并替换内置版本或在线程中管理它,并在超过超时时间后终止线程。令人失望的..... –

回答

0

您可以使用自己的覆盖版本的ContextFactory来执行上下文操作。在makeContext()方法中,您可以从头开始创建上下文,并设置您想要的指令数以及其他设置。

从我实现的一个例子:

public class MyContextFactory extends ContextFactory { 
    protected Context makeContext() { 
     Context cx = new MyContext(this); 
     cx.setOptimizationLevel(0); 
     cx.setLanguageVersion(Context.VERSION_1_8); 
     cx.setInstructionObserverThreshold(100000); 
    return cx; 
    } 
} 

正如你看到的,我也创建我自己的上下文的子类,因为上下文构造这需要作为参数被保护工厂:

public class RhinoContext extends Context { 

    public RhinoContext(ContextFactory factory) { 
     super(factory); 
    } 

} 

然后你应该能够在调用任何脚本之前通过方法ContextFactory.initGlobal(factory)注入自己的上下文工厂的实例。

但是,请注意,我的测试中的指令观察程序仅在优化级别为< = 0时有效。在完全优化的脚本中 - 所有内容都编译为字节码 - 这不起作用。我只用于开发而不是生产系统。

+0

我曾试过这一点。问题是你不能自己调用​​ContextFactory.initGlobal。它将打破尝试调用ContextFactory.initGlobal的RhinoScriptEngine类。它只能被调用一次,并在之后的任何尝试中抛出异常。 –

+0

好的,我不使用RhinoScriptEngine,这可能是为什么这对我有用。我仍然在使用直接描述的Context对象(这里是https://developer.mozilla.org/en-US/docs/Rhino/Embedding_tutorial)使用“旧”的方式。 –