15 sept 2011

GWT: arrays como argumentos desde Java hacia JavaScript mediante JSNI


Todo un tema el intercambios de datos entre los métodos en JavaScript nativo escritos con JSNI y nuestro código Java, básicamente tenemos solo unos pocos tipos ya que aparentemente esta pensado para intercambiar argumentos simples. Repasemos la documentación a ver que tenemos:


Los más prácticos son los básicos: String, boolean y numéricos, los demás requieren de sintaxis especial o son valores opacos que no se prestan demasiado a la manipulación, pero atentos, tenemos a la vista la solución a nuestro problema: los valores de tipo JavaScriptObject.
La documentación da lugar a confusión, ya que aparentemente solo los podríamos usar como valores de retorno de otro método JSNI, pero si revisamos el Javadoc de los tipos de datos disponibles para manejar JSON, vemos que tanto JSONArray como JSONObject poseen el método getJavaScriptObject que tiene como tipo de retorno JavaScriptObject, precisamente lo que podemos pasar como argumento a nuestro código JSNI. Bien, con esto en mente y como muy probablemente utilicemos JSON para el paso de valores es que llegamos al siguiente ejemplo:

package test.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONParser;

public class TestJSNI implements EntryPoint {

 public void onModuleLoad() {

  // creamos un JSONArray de prueba
  JSONArray jsonArray = JSONParser.parseLenient("['rojo','negro','verde']").isArray();
  
  // pasamos como ragumento su JavaScriptObject
  parseArray(jsonArray.getJavaScriptObject());

 }
 
  
  
 private native void parseArray(JavaScriptObject myArray) /*-{

  // mostramos el valor de la primer posición 
  alert(myArray[0]);

 }-*/; 
 
}


Cortito y simple, creamos un JSONArray (incluir en el XML de módulo la línea <inherits name="com.google.gwt.json.JSON" />) para probar y luego lo utilizamos para llamar al método JSNI, el truco como mencionaba es pasar como argumento su objeto JavaScriptObject subyacente y especificar también de este tipo el argumento de nuestro método nativo. Muy útil, seguro una excelente manera para el pasaje de datos con mucha más flexibilidad.



13 sept 2011

GWT: incluir librerías JavaScript externas


Si bien GWT nos proporciona una cantidad muy interesante de métodos para manipular el DOM directamente desde Java, hay ocasiones que es mucho más práctico incluir JavaScript directamente a través de JSNI, si bien no es aconsejable ya que el código incluido no es verificado ni optimizado por el compilador.
Por otra parte, hay ahí fuera miles de librerías y utilidades súper prácticas que es imposible pasar por alto, algunas insustituibles más teniendo en cuenta que GWT tiene serias carencias en algunas áreas, los efectos son un ejemplo, salvo un manojo de buenas herramientas portadas a Java el abanico es escaso, además no siempre tenemos un equivalente a la altura, varias veces los ports terminan siendo más voluminosos que la solución original y a veces con menos posibilidades.
Todo esto nos lleva a más que escribir unas pocas líneas a través de JSNI vernos tentados a incluir librerías externas completas para tener funcionalidades extra en nuestra aplicación, el tema es como lo hacemos.

Lo más básico es escribir un tag link en nuestro archivo home de HTML referenciando el código externo, opcion esta desaconsejada, no solo perdemos el control ya que confiamos en un recurso externo que no sabemos si invariablemente va a estar cuando hagamos el despliegue (con GWT también se hacen pequeños módulos que podemos distribuir independientemente, no solo apps completas), si no que delegamos en el browser las tareas de control del cache y manejo de errores, estamos jugando con fuego se podría decir.
Lo otro es otra incluirlo en nuestro archivo XML de proyecto utilizando la Automatic Resource Inclusion para incluir código externo de una manera más elaborada, pero en este caso siempre lo incluirá más allá de que finalmente lo necesitemos o no.

Precisamente viendo como podemos hacer todo esto de una manera un poco más elegante es que llegamos a la dimensión desconocida de la interfaz Client Bundle para el manejo de recursos externos. Una de las ventajas que ya nos mencionan es que los recursos incluidos a través de ésta pasan a la categoría de recursos cacheados para siempre (repito la importancia  de tener el control de que se cachea y como), lo cual es muy conveniente para recursos que no cambian con el tiempo, los más obvios y por tanto conocidos son imágenes y archivos CSS. Estos cuentan con soporte exaustivo, desde los prácticos sprites de imágenes a cosas más rebuscadas como soporte RTL, pero... y los archivos JS?
En el caso de archivos JavaScript la cosa es un poco acotada, de los tipos disponibles utilizamos el TextResource, que engloba los recursos de "static text content", una linda manera de referirse al JS de toda la vida. 
Otra cosa muy bienvenida que tenemos desde la release 2.4 es la clase ScriptInjector que nos permite crear un tag SCRIPT sin tener que manejar directamente el DOM lo cual es propenso a errores (por ejemplo si nos salteáramos un paso como incluir el tag sin definir el tipo o similares puede fallar), incluso tenemos algunos métodos extra como definir un setCallback en caso de archivos cargados desde una URL, básico pero nada mal.

Comencemos con un ejemplo así vemos como usar esta técnica que seguro nos ayuda a perder el miedo a incluir recursos externos o hacerlo de una manera más consistente, en este caso estaba tratando de utilizar los features de HTML5 Storage, pero en caso de que esta funcionalidad no estuvieran disponible en el cliente quería ofrecer un método alternativo de almacenar datos en el browser, si bien hay excelentes librerías que chequean exhaustivamente el navegador para ver que tenemos disponible (desde almacenamiento Flash hasta características exclusivas de IE entre otras) me decidí por lo simple y utilicé una vieja amiga como es TaffyDB, una muy buena opción para almacenar info en el cliente con algunos métodos muy útiles: contar, ordenar, filtros y algunas cosillas más.


estructura del ejemplo


Allá vamos entonces, proyecto nuevo en Eclipse y creamos un directorio para almacenar Taffy, en este caso bajo el package client/lib, utilizamos la versión minificada de producción taffy-min.js, menos de 20kb... un lujo.
Ahora lo interesante, para incluirla debemos definir una interface que extienda de ClientBundle y tenga la ruta a la librería como argumento de la anotación @Source y un método para referenciarla por el tipo, en mi caso la llame TaffyDBBundle quedando de la siguiente manera:

package testTaffy.client;

import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.TextResource;

public interface TaffyDBBundle extends ClientBundle {
 @Source("lib/taffy-min.js")
 TextResource taffy();
}

Es bastante descriptiva, como mencioné especificamos la ruta al archivo en @Source y definimos un método para accederla del tipo TextResource, en mi caso taffy();
Ahora en el onModuleLoad vamos integrar todo usando el ScriptInjector, aquí tenemos dos opciones: ScriptInjector.fromString y ScriptInjector.fromUrl (no confundir el tipo de retorno con el nombre del método) en este caso como ya tenemos incluida la librería utilizaremos fromString, que recibe como argumento el contenido de nuestro archivo JS, a este lo accedemos mediante el método getText() de la interfaz TextResource que ya implementamos, quedando así:

package test.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.ScriptInjector;

public class TestDB implements EntryPoint {

 public void onModuleLoad() {

  TaffyDBBundle taffy = GWT.create(TaffyDBBundle.class);
  JavaScriptObject result = ScriptInjector.fromString(taffy.taffy().getText()).inject();
  
 }
 
}

Primero creamos nuestro recurso a través de GWT.create quedando del tipo de nuestra interfaz (TaffyDBBundle), luego utilizamos el ScriptInjector.fromString y le pasamos como argumento el llamado a nuestra instancia mediante el método taffy() (podemos llamarlo como queramos) y luego su contenido mediante .getText(), finalmente incluimos el script al DOM mediante .inject();
Para verificar vamos a crear un par de métodos mediante JSNI para verificar que está funcionando, en este caso definimos una base de datos e ingresamos algunos registros, luego verificamos consultando cuantos cumplen con determinada condición:

    private native void createDB() /*-{

  $wnd.sobrinos = TAFFY([ {"id":1,"user":"Hugo","edad":"12"},
        {"id":2,"user":"Paco","edad":"12"},
        {"id":3,"user":"Luis","edad":"12"}  
                        ]);

 }-*/;

 private native void testDB() /*-{

  alert($wnd.sobrinos({"edad":"12"}).count());

 }-*/;


vale recordar que en GWT siempre es conveniente referirse a las variable a través de el objeto $wnd (window) para evitar problemas, ahora juntamos todo:
package testTaffy.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.ScriptInjector;

/**
 * Entry point classes define onModuleLoad().
 */
public class TestTaffyDB implements EntryPoint {

 public void onModuleLoad() {

  TaffyDBBundle taffy = GWT.create(TaffyDBBundle.class);
  JavaScriptObject result = ScriptInjector.fromString(taffy.taffy().getText()).inject();
  
  if (null != result) {
   createDB();
   testDB();
  }
 }

 private native void createDB() /*-{

  $wnd.sobrinos = TAFFY([ {"id":1,"user":"Hugo","edad":"12"},
        {"id":2,"user":"Paco","edad":"12"},
        {"id":3,"user":"Luis","edad":"12"}  
                        ]);

 }-*/;

 private native void testDB() /*-{

  alert($wnd.sobrinos({"edad":"12"}).count());

 }-*/;
}


Utilizo un JavaScriptObject result para verificar que el tag se creo correctamente, al correrlo obtenemos un mensaje de alerta con 3, efectivamente está funcionando ya que hay 3 usuarios cargados en Taffy con el campo edad igual a 12, bastante accesible, como mencionaba hay más métodos útiles disponibles como setCallback al cargar recursos por URL o setWindow para especificar en que ventana queremos colocar el tag SCRIPT, simple y consistente.

Por último juro que busqué que edad tienen los sobrinos del Pato Donald para el ejemplo pero no encontré nada :)



2 sept 2011

Jornadas JIAP 2011

Un poco tarde escribo para comentar sobre las jornadas JIAP 2011 organizadas por AsIAP que fueron del 17 al 19 de agosto en el Centro de Conferencias de la Intendencia de Montevideo.
Según AsIAP su visión es "Por un Uruguay líder en el mundo en Tecnologías de la Información y las Comunicaciones", con semejante lema no podía quedarme fuera de este evento, la consigna esta vez fué "SEGURIDAD: Desafíos de hoy", no es mi tema favorito pero había varias charlas interesantes, asi que haya fuí cámara en mano a ver que que tal.

Este evento y varios que he concurrido tienen un sabor local impresionante, tanto que se da por sentado que todos sabemos donde esta el Centro de Conferencias de la Intendencia de Montevideo, de ahí la ausencia de cartelería tanto en la entrada como dentro del recinto así que pasamos por Informes y allá vamos. El lugar lo encontré un poco corto de espacio, bien para acceder a las salas de conferencia pero chico para montar una serie de stands, de ahí que había que serpentear entre ellos para acceder a las salas, el salon Rojo por ejemplo estaba en un corredor lateral medio escondido, nada grave, solo esquivar el público y no detenerse demasiado frente a los expositores.


Sobre estos solo decir que no había mucho más que cartelería y algun asesor, nada demasiado llamativo, solo uno se la jugó a traer una pizarra táctil gigante cargando Windows 7, estuve toqueteando un poco y respondía bien, lamentablemente no pude sacar fotos pero resultó interesante, me imagino que debe dar buenas posibilidades en enseñanza o algo similar.
Los demás stands solo lo dicho, empresas ya consolidadas (Samsung, Eset,Tilsor,Urudata) y algunas pocas nuevas caras, de nuevo que el recorrido no ayudaba demasiado, incluso el stand de Antel estaba en un lateral medio escondido, quizás el hall de la Intendencia hubiese sido mas cómodo, está claro que se armó el recorrido como se pudo, por ejemplo si a los chicos de la UTU si se les acercaba demasiada gente trancaban un poco el paso.

Sobre esto quiero destacar que tenían los proyectos mas interesantes: un pc refrigerado con vaselina líquida, algo como una cámara que detectaba la posición de un puntero, codigos QR, bastante interesante. Por curiosidad toqué la pecera que contenía el motherboard del pc refrigerado con vaselina y lo noté bastante caliente, al consultar me dijeron que la temperatura aumentaba solo hasta cierto punto, espero que sea como máximo el que tenía en ese momento, sino al fin de la jornada se podrían hacer tortas fritas en la pecera, también tenía el ventilador, supongo que para  ayudar a que circule la vaselina sobre el micro pero creí se podría hacer por convección eliminando piezas mecánicas, igual me gustó ya que estaba novedoso.



Sobre las charlas preferí asistir a las de "Televisión digital interactiva: Situación en la región",
y por último "Implantación de DW Open Source" a la cual pertenecen las fotos que acompañan esta entrada, dejo el temario completo aquí con los slides y filmaciones de las charlas.

Al respecto de estas solo puedo decir que fueron muy flechadas hacia productos, por ejemplo las de "Sistemas de telefonía IP..." básicamente era como Conatel resolvió SU arquitectura básica para SU sistema VoIP, pero sin entrar en demasiados detalles, mucho menos técnicos.
Es como si te dijera que para aumentar la potencia de un auto le pongas un motor más grande, pero no te aclare que tipo de motor, o como ponerlo, cosas así, otras casi eran demos de productos ("Tecnología CISCO en videovigilancia", "Printing Solutions Samsung") y esta es hasta graciosa: "Construyendo la interoperabilidad por medio de estándares", nada raro solo que venía de parte de MICROSOFT, me imagino que serían estándares de facto, similar a la cartelería de Oracle que abogaba por la innovación, un poco desentonado con los últimas demandas impuestas contra todos los que usen Java y demás, solo marketing.



La de televisión digital aunque interesante me recordó que nuevamente vamos a ser tomadores natos de tecnología, esta vez de los brasileños (el middleware Ginga es desarrollado por ellos), cuestión de mercados. Al escuchar de donde procedía solo espere que no usara LUA como lenguaje de scripting, pero sí, Ginga-NCL lo utiliza ampliamente, aclaro que no es que el lenguaje me parezca malo, solo que al ser otro desarrollo brasileño me la ví venir.

La de Conatel mediana (no mala tampoco) como mencioné y la de DataWarehouse Open Source para ASSE bastante más interesante, contando un poco sobre arquitectura, productos seleccionados, problemas encontrados (mencionaron más de 19 departamentos, gente registrada que todavía no nació, otros de más de 120 años), adjunto algunas fotos pero en los PDF's de las charlas lo puden ver mucho mejor. Como conclusión un evento bastante ameno, mejorable como todo pero interesante, y al ser de carácter genérico mas allá de la consigna sobre seguridad es bien heterogéneo, soluciones privativas, otras Open Source, poco ruido por lo "Cloud" afortunadamente y lo fundamental y más importante, promotoras lindas que amenizen la jornada, como para no tirar un par de fotitos.