2012-04-20 7 views
5

¿Tiene el motor de Rhino una API que puede detener la ejecución de una secuencia de comandos en el medio? Por ejemplo, tengo un archivo de script en el que hay un bucle infinte. ¿Cómo puedo detener la ejecución en el medio?Detención del motor de Rhino en medio de la ejecución

Por supuesto, puedo detener el jvm que inició el motor de Rhino en para ejecutar el script. Pero no quiero matar toda la sesión de jvm por ese motivo, ya que he iniciado el script de forma programática y el motor de Rhino también se ejecuta en la misma JVM que mi aplicación.

Respuesta

5

Detener la ejecución de ejecutar JavaScript se puede hacer de la siguiente manera.

1) Cree un depurador ficticio y adjúntelo al contexto creado inicialmente.

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

El código ObservingDebugger se ve de la siguiente manera.

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) { } } 

clase ObservingDebugger gestionará la variable booleana "isDisconnected" y cuando el usuario hace clic en el botón de parada (quiere detener la ejecución), entonces esta variable se establece en true. Una vez que la variable se establece en verdadero de la siguiente manera, la ejecución de Rhino finalizará inmediatamente.

observingDebugger.setDisconnected(true); 
-2

El motor Rhino doesn't appear tener ningún mecanismo para hacer esto (mala Rhino!) Y es difícil decir si se crea roscas internamente, por lo que la única solución que tienes es crear un ThreadGroup, cargar y ejecutar el Rhino motor y su secuencia de comandos desde dentro de un hilo en ese grupo, y cuando quiera matarlo, use ThreadGroup.stop(). Sí, está en desuso, pero realmente no hay otra forma de hacerlo, dado que no hay cooperación por parte de la biblioteca de Rhino.

+0

@ Donal: esto podría pr Probablemente no funcione porque una vez que creo un nuevo hilo y empiezo a cargar y ejecutar el motor de Rhino desde el momento en que se llama al método evaluateReader() en el contexto, la ejecución del hilo se completa y el motor de Rhino gestiona internamente la ejecución. – Syam

+0

Es por eso que sugerí ponerlo en su propio grupo de hilos; cualquier otro subproceso creado por Rhino seguirá estando en ese grupo de subprocesos (o un grupo de subprocesos hijo) por lo que aún será posible eliminarlos todos_. –

2

Para cualquier otra persona en busca de una solución, el Javadoc para ContextFactory detalles cómo detener un script en ejecución más de 10 segundos:

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

+0

El enfoque ContextFactory personalizado funciona de manera brillante. Si tiene problemas para leer el javadoc del java, hay una versión HTML aquí: http://www.jarvana.com/jarvana/view/org/mozilla/rhino/1.7R3/rhino-1.7R3-javadoc.jar!/org /mozilla/javascript/ContextFactory.html – kevinjansz

+0

Me pregunto sobre el impacto en el rendimiento de este y el método del depurador. ¿Algunas ideas? – HRJ

+0

Me imagino que el método del depurador tiene algún impacto en el rendimiento ya que el contexto genera información de depuración. La solución ContextFactory simplemente se activa después de que se haya ejecutado un cierto número de instrucciones. – bigspotteddog

0

que ejecutar secuencias de comandos en un nuevo hilo usando una ExecutorService y con fecha de salida 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!"); 
    } 

Tenga en cuenta que este enfoque no se detendrá el hilo de ejecutar el guión!Con el fin de hacerlo, ya que el hilo de ejecución se notificará la secuencia de comandos que ser interrumpido, puede crear un ContextFactory personalizada que supervisa periódicamente esta situación:

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; 
    } 
} 

Antes de crear cualquier objeto de contexto, es necesario configurar la aplicación para utilizar esta ContextFactory por defecto, simplemente invocar

InterruptableContextFactory.init() 

Dentro de su método llamado de rescatable, puede capturar el 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(); 
    } 
Cuestiones relacionadas