2012-04-20 82 views
5

犀牛引擎是否有一个可以停止执行中间脚本的API。例如,我有一个脚本文件,其中 有一个无限循环。我怎样才能在中间停止执行?停止犀牛引擎执行中

当然,我可以阻止启动Rhino引擎的jvm改为 。但我不想因为这个原因杀死整个jvm会话,因为我已经以编程方式启动脚本,并且Rhino引擎也与我的应用程序在相同的JVM中运行。

回答

5

停止运行JavaScript的执行可以通过以下方法完成。

1)创建一个虚拟调试器并将其附加到最初创建的上下文中。

mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger,new Integer(0));
mContext.setGeneratingDebug(true);
mContext.setOptimizationLevel(-1);

ObservingDebugger代码如下所示。

import org.mozilla.javascript.Context; 
import org.mozilla.javascript.Scriptable; 
import org.mozilla.javascript.debug.DebugFrame; 
import org.mozilla.javascript.debug.DebuggableScript; 
import org.mozilla.javascript.debug.Debugger; 

public class ObservingDebugger implements Debugger 
{ 
boolean isDisconnected = false; 

private DebugFrame debugFrame = null; 

public boolean isDisconnected() { 
    return isDisconnected; 
} 

public void setDisconnected(boolean isDisconnected) { 
    this.isDisconnected = isDisconnected; 
    if(debugFrame != null){ 
     ((ObservingDebugFrame)debugFrame).setDisconnected(isDisconnected); 
    } 
} 

public ObservingDebugger() { 

} 

public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) 
{ 
    if(debugFrame == null){ 
     debugFrame = new ObservingDebugFrame(isDisconnected); 
    } 
    return debugFrame;  
} 

@Override 
public void handleCompilationDone(Context arg0, DebuggableScript arg1, String arg2) { } } 
// internal ObservingDebugFrame class 
class ObservingDebugFrame implements DebugFrame 
    { 
boolean isDisconnected = false; 

public boolean isDisconnected() { 
    return isDisconnected; 
} 

public void setDisconnected(boolean isDisconnected) { 
    this.isDisconnected = isDisconnected; 
} 

ObservingDebugFrame(boolean isDisconnected) 
{ 
    this.isDisconnected = isDisconnected; 
} 

public void onEnter(Context cx, Scriptable activation, 
     Scriptable thisObj, Object[] args) 
{ } 

public void onLineChange(Context cx, int lineNumber) 
{ 
    if(isDisconnected){ 
     throw new RuntimeException("Script Execution terminaed"); 
    } 
} 

public void onExceptionThrown(Context cx, Throwable ex) 
{ } 

public void onExit(Context cx, boolean byThrow, 
     Object resultOrException) 
{ } 

@Override 
public void onDebuggerStatement(Context arg0) { } } 

ObservingDebugger类会管理的布尔变量“isDisconnected”,当用户点击停止按钮(要停止执行),那么这个变量设置为true。一旦将变量设置为true,Rhino执行将立即终止。

observingDebugger.setDisconnected(true); 
-2

犀牛引擎doesn't appear有这样做的机制(坏的犀牛!),很难说它是否在内部创建线程,所以唯一的解决办法是创建一个ThreadGroup,加载并执行Rhino引擎及其脚本从该组中的线程中移除,并且当您想要将其关闭时,请使用ThreadGroup.stop()。是的,它已被弃用,但由于Rhino库没有合作,所以没有其他办法可以做到。

+0

@多纳尔:这可能PR obably不起作用,因为一旦我创建新线程并开始加载并执行Rhino引擎,一旦上下文的evaluateReader()方法被调用,线程执行完成并且Rhino引擎在内部管理执行。 – Syam 2012-04-26 10:21:18

+0

这就是为什么我建议把它放在自己的线程组中;由Rhino创建的任何其他线程仍将位于该线程组(或一个子线程组)中,因此仍然有可能将它们全部__全部抛出。 – 2012-04-26 12:27:56

2

为别人寻找一个解决方案,为ContextFactory的Javadoc详细介绍了如何阻止脚本运行时间超过10秒:

https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/ContextFactory.java

+0

自定义的ContextFactory方法出色地工作。如果您在阅读Java中的javadoc时遇到问题,请在这里阅读HTML版本:http://www.jarvana.com/jarvana/view/org/mozilla/rhino/1.7R3/rhino-1.7R3-javadoc.jar!/org /mozilla/javascript/ContextFactory.html – kevinjansz 2013-05-02 00:10:20

+0

我想知道这个和调试器方法的性能影响。有任何想法吗? – HRJ 2015-09-16 08:20:16

+0

我会想象调试器方法会对性能产生一些影响,因为上下文正在生成调试信息。 ContextFactory解决方案只是在执行了一定数量的指令之后触发。 – bigspotteddog 2015-09-16 18:18:32

0

我使用的ExecutorService在一个新的线程执行脚本和超时的future.get

ExecutorService executor = Executors.newSingleThreadExecutor(); 

    Future<?> future = executor.submit(threadEvaluation); 

    try { 
     System.out.println("Started.."); 
     future.get(100, TimeUnit.MILLISECONDS); 
     System.out.println("Finished!"); 
    } catch (TimeoutException e) { 
     future.cancel(true); 
     System.out.println("Terminated!"); 
    } 

请注意,这种方法不会停止执行脚本的线程!为了做到这一点,因为线程执行你的脚本将被通知被打断,你可以创建一个定期监视这种情况的自定义ContextFactory:

public class InterruptableContextFactory extends ContextFactory { 

    public static boolean initialized = false; 

    public static void init() { 
     if (!initialized) { 
      ContextFactory.initGlobal(new InterruptableContextFactory()); 
      initialized = true; 
     } 
    } 

    @Override 
    protected void observeInstructionCount(Context cx, int instructionCount) { 
     System.out.println(instructionCount + " javascript instructions!"); 
     if (Thread.currentThread().isInterrupted()) { 
      throw new Error("script execution aborted"); 
     } 
    } 

    @Override 
    protected Context makeContext() { 
     Context cx = super.makeContext(); 
     //set a number of instructions here 
     cx.setInstructionObserverThreshold(10000); 
     return cx; 
    } 
} 

创建任何背景对象之前,你需要配置你的应用程序使用此ContextFactory为默认值,只需调用

InterruptableContextFactory.init() 

内,您的可赎回的呼叫的方法,你可以捕捉到错误:

try { 
     cx.setOptimizationLevel(9); 
     cx.setInstructionObserverThreshold(10000); 
     ScriptableObject scope = cx.initStandardObjects(); 

     // your code here 

    } catch (Error e) { 
     System.out.println("execution was aborted: " + e.getMessage()); 
    } finally { 
     Context.exit(); 
    }