如何杀死 Rhino 脚本
How to kill a Rhino script
我们正在使用 Rhino 在我们的 Java 应用程序中执行 Java 脚本。我们使用了一些 Rhino 特有的功能,因此我们无法升级到 Nashorn。
我们的问题是脚本是用户创建的,我们执行的时候,如果出现死循环之类的错误,就一直执行下去。我们想将时间限制设置为 30 秒。
有没有办法在超时时终止脚本?
您可以通过创建虚拟调试器来停止来自 运行 的循环,并将其直接添加到 java 脚本中,如下所示:
mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger, new Integer(0));
mContext.setGeneratingDebug(true);
mContext.setOptimizationLevel(-1);
然后通过 java 程序,您创建一个 class 如下所示:
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) { } }
然后设置程序的定时器,你导入:
import java.util.Timer;
然后为 ObservingDebugger 设置定时器首选项:
timer.schedule(new TimerTask() {
@Override
public void run() {
// code here
}
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);
您应该扩展 ContextFactory
class 并覆盖方法 observeInstructionCount(Context ctx, int instructionCount)
。 Rhino 会定期调用此方法,您可以通过以下方式检查 运行 到目前为止的时间:
public class ScriptDynamicScopeFactory extends ContextFactory {
@Override
protected Context makeContext() {
ScriptContext ctx = new ScriptContext();
ctx.setInstructionObserverThreshold(10000);
return ctx;
}
@Override
protected void observeInstructionCount(Context ctx, int instructionCount) {
long currentTime = System.currentTimeMillis();
long executionTime = (currentTime - ((ScriptContext) ctx).startTime());
// do something if execution time is greater then your timeout
}
}
请注意,您还需要覆盖 makeContext()
以设置调用观察者的频率。请记住,这是执行的指令数,这意味着它不会每隔 X 毫秒就被一致地调用一次。如果一条指令需要很多时间(例如,调用您的 Java 应用程序),这可能效果不佳,但我认为它在几乎所有情况下都能很好地完成工作。
我们正在使用 Rhino 在我们的 Java 应用程序中执行 Java 脚本。我们使用了一些 Rhino 特有的功能,因此我们无法升级到 Nashorn。 我们的问题是脚本是用户创建的,我们执行的时候,如果出现死循环之类的错误,就一直执行下去。我们想将时间限制设置为 30 秒。 有没有办法在超时时终止脚本?
您可以通过创建虚拟调试器来停止来自 运行 的循环,并将其直接添加到 java 脚本中,如下所示:
mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger, new Integer(0));
mContext.setGeneratingDebug(true);
mContext.setOptimizationLevel(-1);
然后通过 java 程序,您创建一个 class 如下所示:
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) { } }
然后设置程序的定时器,你导入:
import java.util.Timer;
然后为 ObservingDebugger 设置定时器首选项:
timer.schedule(new TimerTask() {
@Override
public void run() {
// code here
}
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);
您应该扩展 ContextFactory
class 并覆盖方法 observeInstructionCount(Context ctx, int instructionCount)
。 Rhino 会定期调用此方法,您可以通过以下方式检查 运行 到目前为止的时间:
public class ScriptDynamicScopeFactory extends ContextFactory {
@Override
protected Context makeContext() {
ScriptContext ctx = new ScriptContext();
ctx.setInstructionObserverThreshold(10000);
return ctx;
}
@Override
protected void observeInstructionCount(Context ctx, int instructionCount) {
long currentTime = System.currentTimeMillis();
long executionTime = (currentTime - ((ScriptContext) ctx).startTime());
// do something if execution time is greater then your timeout
}
}
请注意,您还需要覆盖 makeContext()
以设置调用观察者的频率。请记住,这是执行的指令数,这意味着它不会每隔 X 毫秒就被一致地调用一次。如果一条指令需要很多时间(例如,调用您的 Java 应用程序),这可能效果不佳,但我认为它在几乎所有情况下都能很好地完成工作。