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.-