jueves, 3 de junio de 2010

Scripting con GX Java

Amigos, luego de una -demasiado- larga ausencia, aquí estamos nuevamente para compartir de alguna forma en torno a GeneXus.
Hoy me animo a postear algo sobre el tema de scripting en Java.

Lo de hacer scripts para dejar las aplicaciones con cierto dinamismo, siempre me ha llamado bastante la atención. Al punto que siempre ando buscando en qué poder usar una solución de ese tipo.

Y, así y todo, estaba tranquilo por la vida hasta que -hace unos meses atrás- leí en el foro: "Hola gente, quería saber si es posible agregar algun código Javascript en un procedimiento?".
De inmediato reaccioné con lo de JScriptSrc y JSEvent , y un textblock-raw-html y no sé qué otra cosa que no tenía nada que ver con la pregunta...
Después de un rato me quedó claro que por el lado del cliente no era el tema. Que no era un javascript a ser interpretado por el browser, que tenía que ser server-side y punto!. O capaz que ni se trataba de algo web...

Después de investigar un poco descubrí que había miles de cosas respecto de scripting en el mundo Java y que el mismísimo Javascript se puede usar desde hace un buen tiempo.
No voy a entrar en detalle de las implementaciones que existen, ni de la historia del tema, ni de todos los lenguajes de script que podríamos usar. Sólo les cuento que el scriptengine Rhino viene incluido con Java6 y que para empezar a usarlo bastan una pocas líneas de java embebido en algún programa que hagamos con GX.

Aquí un ejemplo para probar en un procedure.

Primero ponemos algunas funciones javascript en una variable:
&jscript = 'function f1(parm1)' + newline() +
'{' + newline() +
' //aquí el código' + newline() +
'}' + newline() +
'function f2(parm1)' + newline() +
'{' + newline() +
' //aquí el código' + newline() +
'}'

Luego el java para instanciar el scriptengine:
java javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager();
java javax.script.ScriptEngine engine = manager.getEngineByName("javascript");


Y luego cargar nuestras funciones javascript e invocar una de ellas:
java try {
java engine.eval([!&jscript!]);
java javax.script.Invocable invocableEngine = (javax.script.Invocable) engine;
java Object ob = invocableEngine.invokeFunction([!&funcionJS!],[!&parm!]);
java [!&out!] = ob.toString();}
java catch(javax.script.ScriptException e){java System.out.println(e);}
java catch (java.lang.NoSuchMethodException e) {e.printStackTrace();}


Las variables &funcionJS, &parm y &out corresponden al nombre de la función, un parámetro y el retorno, respectivamente.

Un problema se nos puede dar con el pasaje de parámetros. En este ejemplo sólo tenemos la posibilidad de pasar uno, y tiene que ser string. Pero si pasamos un string JSON, en el javascript podemos evaluarlo e instanciar un objeto con el que podemos trabajar (podría ser una lista de parámetros, por ejemplo).

Algunas cosas entretenidas que se pueden hacer:
  • usar otras classes java desde un script, por ejemplo conectar a una BD (JDBC)
  • compilar a bytecode java, antes de invocar
  • quién sabe qué más!


Bueno, un saludo a todos y hasta la próxima.-

8 comentarios:

  1. Miguel:
    Tu tip esta bueno para darle mas dinamismos a la aplicacion.
    Por ejemplo, se podria agregar validaciones definidas por el usuario o reglas definidas por el usuario.
    Hariamos un programa que permita escribir las reglas en un lenguaje facil para el usuario y que las mismas sean traducidas a javascript y luego la aplicacion las ejecutaria.

    Esta bueno. Gracias por compartirlo.

    ResponderEliminar
  2. Esté muy bueno, no sabía que Rhino venía con la JRE.
    Un caso de uso que pienso que puede estar interesante es para cálculos, por ejemplo de impuestos, donde uno pone todas las posibles entradas a disposición del script y el cálculo se define como una fórmula javascript.
    Creo que había un collaborative project trabajando en expresiones para cálculos dinámicos, pero ahora la wiki está caída y no lo puedo buscar.

    ResponderEliminar
  3. Muy buena idea.

    Se puede trabajar en hacer algo "multiplatadorma", ya que se puede buscar que los Script generados sean también JScript .NET compatibles, con eso podrían correr en .NET (me parece mucho trabajo)

    Un programa genera los Script y otro los evalúa.

    La otra alternativa (que mejora la compatibilidad, ya que JScript.NET se quedó) es usar Rhino en .NET
    http://www.codeproject.com/KB/cs/EmbeddingJSCS.aspx

    Interesante para plantear un proyecto en torno a la generación y evaluación de script dinámico con GeneXus Java/.NET .

    ResponderEliminar
  4. Enrique:

    Había pensado que para el usuario bastaba Javascript. Es cierto que hay diferentes tipos de usuarios..., pero quien tenga que escribir validaciones y reglas debiera estar preparado para algo como javascript, o -al menos- apoyarse en un técnico.
    Tengo un proyecto en el GXServer público, pero no he podido darle mucho tiempo. Se llama ufProject, por si lo quieren ver.
    Y claro que falta lo de net. Veamos si David nos pasa algunos tips ;).
    salu2!!!

    ResponderEliminar
  5. Si esta muy weno, yo ya lo había probado hace algun tiempo en proyectos antiguos, claro que con Java nativo no JavaScript. Y se pueden hacer arta cosas. Genial !!!!

    ResponderEliminar
  6. el blog y el tema me parecen muy bueno, soy estudiante de informatica y estoy haciendo mi tesis en genexus..tengo una consulta y espero que puedan responder, estoy haciendo un sistema de facturacion y quiero integra la factura electronica al sistema... pero no tengo muy claro si hay una forma de integrarlo a genexus?...espero que tenga una respuesta.aqui les dejo mi mail.
    almgonza@gmail.com

    ResponderEliminar
  7. A pesar de vivir en Argentina, constantemente viajo a Chile por razones laborales, Trabajo en el rubro de informática y por eso son muchas las veces en el año que decido obtener Pasajes a Chile para hacer trabajos allí

    ResponderEliminar