I execute scripts in a new thread using an ExecutorService and timed-out 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!");
}
Notice that this approach will not stop the thread executing the script! In order to do so, as the thread executing your script will be notified to be interrupted, you can create a custom ContextFactory that monitors periodically this situation:
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;
}
}
Before creating any Context object, you need to configure your application to use this ContextFactory as default, just invoke
InterruptableContextFactory.init()
Inside your Callable's call method, you can capture the Error:
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();
}