Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java scripting API - how to stop the evaluation

i have writen a servlet that recives a java script code and process it and returns the answer. for that i have used the java scripting API

in the code below if script = "print('Hello, World')"; the code will end properly print "hello world". but if script = "while(true);" the script will loop endlessly.

import javax.script.*;
public class EvalScript {
    public static void main(String[] args) throws Exception {
        // create a script engine manager
        ScriptEngineManager factory = new ScriptEngineManager();
        // create a JavaScript engine
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        // evaluate JavaScript code from String
        engine.eval(script);
    }
}

my question is how do i kill the eval process in case it takes too long (lets say 15 sec)?

thanks

like image 267
special0ne Avatar asked Oct 21 '09 14:10

special0ne


1 Answers

Here's some code showing the Future implementation and the Thread.stop() one. This is an interesting problem, and it points out the need for a hook in a ScriptEngine to be able to halt whatever script it's running for whatever reason. I wonder whether this would break the assumptions in most implementations since they assume eval() will be executed in a single-threaded (blocking) environment?

Anyway, the results of executing the code below:

// exec with Thread.stop()
$ java ExecJavascript 
Java: Starting thread...
JS: Before infinite loop...
Java: ...thread started
Java: Thread alive after timeout, stopping...
Java: ...thread stopped
(program exits)

// exec with Future.cancel()
$ java ExecJavascript 1
Java: Submitting script eval to thread pool...
Java: ...submitted.
JS: Before infinite loop...
Java: Timeout! trying to future.cancel()...
Java: ...future.cancel() executed
(program hangs)

Here's the full program:

import java.util.concurrent.*;
import javax.script.*;

public class ExecJavascript
{
private static final int TIMEOUT_SEC = 5;
public static void main( final String ... args ) throws Exception 
{
    final ScriptEngine engine = new ScriptEngineManager()
        .getEngineByName("JavaScript");
    final String script = 
        "var out = java.lang.System.out;\n" +
        "out.println( 'JS: Before infinite loop...' );\n" +
        "while( true ) {}\n" +
        "out.println( 'JS: After infinite loop...' );\n";
    if ( args.length == 0 ) {
        execWithThread( engine, script );
    }
    else {
        execWithFuture( engine, script );
    }
}

private static void execWithThread( 
    final ScriptEngine engine, final String script )
{
    final Runnable r = new Runnable() {
        public void run() {
            try {
                engine.eval( script );
            }
            catch ( ScriptException e ) {
                System.out.println( 
                    "Java: Caught exception from eval(): " + e.getMessage() );
            }
        }
    };
    System.out.println( "Java: Starting thread..." );
    final Thread t = new Thread( r );
    t.start();
    System.out.println( "Java: ...thread started" );
    try {
        Thread.currentThread().sleep( TIMEOUT_SEC * 1000 );
        if ( t.isAlive() ) {
            System.out.println( "Java: Thread alive after timeout, stopping..." );
            t.stop();
            System.out.println( "Java: ...thread stopped" );
        }
        else {
            System.out.println( "Java: Thread not alive after timeout." );
        }
    }
    catch ( InterruptedException e ) {
        System.out.println( "Interrupted while waiting for timeout to elapse." );
    }
}

private static void execWithFuture( final ScriptEngine engine, final String script )
    throws Exception
{
    final Callable<Object> c = new Callable<Object>() {
        public Object call() throws Exception {
            return engine.eval( script );
        }
    };
    System.out.println( "Java: Submitting script eval to thread pool..." );
    final Future<Object> f = Executors.newCachedThreadPool().submit( c );
    System.out.println( "Java: ...submitted." );
    try {
        final Object result = f.get( TIMEOUT_SEC, TimeUnit.SECONDS );
    }
    catch ( InterruptedException e ) {
        System.out.println( "Java: Interrupted while waiting for script..." );
    }
    catch ( ExecutionException e ) {
        System.out.println( "Java: Script threw exception: " + e.getMessage() );
    }
    catch ( TimeoutException e ) {
        System.out.println( "Java: Timeout! trying to future.cancel()..." );
        f.cancel( true );
        System.out.println( "Java: ...future.cancel() executed" );
    }
} 
}
like image 121
Chris Winters Avatar answered Nov 03 '22 03:11

Chris Winters