2011-12-23 17 views
15

Estoy usando el paquete javax.script. * Del JDK. Específicamente, estoy usando el motor JavaScript, que, por lo que he leído, parece estar basado en un intérprete Java-JavaScript desarrollado por Mozilla llamado Rhino.Interpretación de JavaScript en Java con Rhino: pausar/reanudar scripts

Lo que espero lograr es básicamente tener mi JavaScript capaz de "pausar" a sí mismo en un cierto punto del código (por ejemplo, a mitad de una llamada de función) y solo reanudarse más tarde cuando Java lo permita asi que.

Para ilustrar lo que quiero decir, imaginar el código JavaScript:

function myJSFunction() { 
    print("Hello "); 
    mysteriousPauseFunction(); // this is the part I'm wondering about. basically, the script should break here and resume later at Java's discretion... 
    // upon reaching this comment, we know now that Java has told JavaScript that it's okay to resume, so the next line will now be executed... 
    print("world"); 
} 

Si la "pausa"/"ruptura" parte implica la unión en función de Java y se lleva una referencia a la ScriptEngine actual o lo que sea, que es genial conmigo Creo que eso es lo que probablemente implicará: detener el JavaScript desde Java.

Hice algunos google y encontré que la palabra clave aquí parece ser "continuaciones". Por lo que puedo decir, Rhino solo admite continuaciones en modo interpretado (en comparación con el modo compilado), lo que veo se logra al establecer el "contexto" en -2. Dado que el JDK ScriptEngine incorporado no parece mencionar nada acerca de los contextos (o tal vez me falta), ¿significa esto que tengo que descargar y usar la biblioteca Rhino de Mozilla directamente en su lugar?

¿Y son las continuación de Rhino lo que necesito para lograr esto? He encontrado a useful tutorial en continuaciones de Rhino, pero después de leerlo, no estoy 100% seguro de si esto podrá lograr lo que describí anteriormente. Si este es lo que estoy buscando, entonces mi siguiente pregunta es sobre la "serialización" mencionada: ¿esto significa que cuando reinicie mi script, todas las variables se habrán desactivado a menos que las serialice?

Actualización: Parece que esto es posible con Rhino. Esto es lo que tengo hasta ahora en mi JavaScript; después del código, voy a explicar lo que hace ...

var end = new Continuation(); 

function myJSFunction() 
{ 
    print("Hello "); 
    var kont = new Continuation(); 
    storePause(script, kont); // script is previously bound by Java into the JavaScript. it is a reference to the script itself. 
    end(); 
    print("world"); 

} 

Mi "storePause()" función es una función de Java que he escrito, y se une a la de JavaScript, pero en este momento, no hace nada Mi próximo objetivo será desarrollar su código de forma tal que almacene la información de continuación y guiones como objetos Java, para que Java pueda reanudar el guión más tarde.

En este momento, lo que hace es pausar/"romper" el script después de imprimir "Hola" pero antes de imprimir "mundo", por lo que esto me demuestra que es posible pausar un script de esta manera.

Por lo tanto, todo lo que debería haber dejado para averiguar en este momento es cómo reanudar una continuación. Tenga en cuenta que lo anterior funciona con el motor de scripts JDK de forma predeterminada (no he tenido que preocuparme por el modo interpretado frente al modo compilado en este punto, parece ser el modo interpretado por defecto), pero parece el proceso de reanudar un script requerirá la biblioteca de Rhino de Mozilla.

Respuesta

5

De acuerdo, me llevó muchas horas de buscar documentación, tutoriales y ejemplos, y también publicar aquí y en el Rhino Google Group, pero me las arreglé para compilar una solución de trabajo. Dado que parece que no hay un ejemplo completo, publicaré mis hallazgos aquí para cualquier persona que tropiece con esto en el futuro.

En realidad, mis resultados son probablemente demasiado tiempo para publicar aquí, así que decidí escribir un tutorial sobre mi blog:

http://www.joshforde.com/blog/?p=7

la esperanza de que ayude a alguien. Hasta donde yo sé, este es el único tutorial completo de Rhino que muestra cómo hacer todo lo siguiente: inicializar Rhino, cargar un script desde un archivo JavaScript (* .js), vincular automáticamente todas las funciones en una clase Java en particular (por ejemplo, ScriptFunctions) como funciones globales en JavaScript, y finalmente llama a una función de JavaScript y maneja las continuaciones para esa llamada.

Básicamente, el problema era que tenía que descargar primero el código fuente de Mozilla Rhino (porque la versión empaquetada con el JDK es obsoleto y no soporta continuaciones), reescribir toda mi código para utilizar el funcionario La sintaxis del paquete Rhino (es muy diferente de la sintaxis ScriptingEngine de JDK), escribe una función Java que arroja una excepción ContinuationPending y la vincula a JavaScript para que JavaScript pueda llamarla (porque arrojar un ContinuationPending directamente desde JavaScript produce una JavaScriptException lanzada, no una Continuación. Lanzando e lanzando, e incluso tratando de llamar a getCause() en JavaScriptException resulta en nulo), y luego en mi código Java que llama a mi función de JavaScript ("myJSFunction" en mi ejemplo original), tiene try/catch blocks para buscar un ContinuaciónPending (whi ch es una excepción), y luego usa ContinuationPending para reanudar el script.

Phew. Fue difícil, pero ahora todo vale la pena.

+0

El sitio de blog no responde. –

+1

@JesseGlick gracias por el aviso. Parece que necesito mover mi sitio a un nuevo servidor web o algo. Mientras tanto, aquí hay una versión de archive.org: https://web.archive.org/web/20130730231256/http://www.joshforde.com/blog/index.php/2011/12/tutorial-continuations-in -mozilla-rhino-a-javascript-intérprete-para-java / – Josh1billion

-1

Usted podría utilizar esperar/notificar:

public final class Pause { 
    private final Object lock = new Object(); 

    public void await() throws InterruptedException { 
    synchronized (lock) { 
     lock.wait(); 
    } 
    } 

    public void resumeAll() { 
    synchronized (lock) { 
     lock.notifyAll(); 
    } 
    } 
} 

Uso:

final Pause pause = new Pause(); 

class Resumer implements Runnable { 
    @Override public void run() { 
    try { 
     Thread.sleep(5000); 
     pause.resumeAll(); 
    } catch (InterruptedException e) { 
     Thread.currentThread().interrupt(); 
    } 
    } 
} 
new Thread(new Resumer()).start(); 

SimpleBindings bindings = new SimpleBindings(); 
bindings.put("pause", pause); 
String script = "print('Hello, ');\n" 
       + "pause.await();\n" 
       + "println('ECMAScript!');\n"; 
new ScriptEngineManager().getEngineByName("ECMAScript") 
         .eval(script, bindings); 

Ésta es una solución relativamente simple como usted no menciona ningún otro tipo. wait() hace que el hilo se bloquee, lo que no sería aceptable en todos los entornos.Tampoco hay una manera fácil de identificar qué subprocesos están esperando en la instancia Pause si desea ejecutar scripts al mismo tiempo.

Nota: el InterruptedException en await() debe ser manejado ya sea por la persona que llama o haciendo algo más sensible en await().

+0

Gracias, pero lo que estoy buscando utilizar es la funcionalidad real de "continuaciones" de Rhino. Después de días de investigación y depuración, finalmente encontré cómo lograr esto, así que publicaré una respuesta para cualquiera que busque esta información en el futuro. – Josh1billion

0

Usted no explica por qué estaba haciendo esto, pero yo estaba emulando un programa que interactúa con un usuario final, así:

print('Hello!'); 
a=Number(input('enter a number')); 
b=Number(input('and another number')); 
print('the sum of '+a+' plus '+b+' is '+(a+b)) 

Tengo que funcione simplemente mediante la creación de una impresión y una función de entrada en javascript que comprueba el estado del programa.

se puede ver una demo here.

todo está escrito en javascript para que pueda mirar el código fuente con cualquier navegador.

Espero que ayude

Cuestiones relacionadas