2014-01-27 64 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)使用「舊」的方式。 –