Incluyendo Simile Timeline en una aplicación ADF Faces.

Escenario

El MIT (Instituto Tecnológico de Massachussetts) ofrece herramientas de manejo y visualización de datos fáciles de usar y, en principio integrables en aplicaciones web cliente, a través del proyecto SIMILE.  Concretamente, para cubrir la necesidad de visualizar eventos en una línea temporal, dispone del widget timeline.  Se trata de una librería javascript que permite justamente eso, visualizar cronológicamente información.  El software se ofrece bajo una licencia BSD.  Se proporciona documentación de cómo se puede incluir una línea temporal en una página HTML.  Aquí lo que vamos a ver es cómo hacerlo en una página ADF Faces.  Nuestra página ADF dispone de un campo lista desplegable. El usuario seleccionará un valor determinado de dicha lista y pulsará un botón de consulta. En ese momento, deberá mostrarse la linea temporal con el calendario correspondiente a la opción elegida.

La estructura

Para usar la linea temporal es necesario incluir los scripts de Simile en nuestro proyecto, en un subdirectorio dentro de public_html. Una vez hecho esto, crearemos tres servlets, a saber:

  • Un primer servlet que extraerá la información que va a aparecer en la línea temporal y generará un XML con la estructura que espera Simile. El parámetro que necesita para extraer la información lo tomará de la sesión.  No obstante, se le pasará un parámetro con los milisegundos de la hora actual para evitar que algunos navegadores (I.E., de hecho) no invoquen al servlet por segunda vez en una sesión al asumir erróneamente que, siendo la misma URL, los datos devueltos deben ser los mismos (incorrecto, ya que los parámetros se están pasando a través de la sesión).
  • Otro servlet que creará la parte jscript que va en el head de la página HTML final.
out.println("<script src=\"simile-timeline-api/timeline-api.js\" type=\"text/javascript\"></script>");
 out.println ("<script>");
 out.println ("var tl1, tl2;");
 out.println ("function onLoad() {");
 out.println ("var ejercicio=new Date().getFullYear();");
 out.println ("var eventSource = new Timeline.DefaultEventSource();");
 out.println ("");
 out.println ("            var theme = Timeline.ClassicTheme.create();");
 out.println ("");
 out.println ("            var date = \"" + getFechaActual() + "\"");
 out.println ("            var bandInfos = [");
 out.println ("                Timeline.createBandInfo({");
 out.println ("                    eventSource:    eventSource,");
 out.println ("                    date:           date,");
 out.println ("                    width:          \"70%\",");
 out.println ("                    intervalUnit:   Timeline.DateTime.MONTH,");
 out.println ("                    intervalPixels: 200");
 out.println ("                }),");
 out.println ("                Timeline.createBandInfo({");
 out.println ("                    eventSource:    eventSource,");
 out.println ("                    date:           date,");
 out.println ("                    width:          \"30%\",");
 out.println ("                    intervalUnit:   Timeline.DateTime.YEAR,");
 out.println ("                    intervalPixels: 200,");
 out.println ("                    overview: true,");
 out.println ("                    trackHeight:    10,");
 out.println ("                    trackGap:       5");
 out.println ("                })");
 out.println ("            ];");
 out.println ("            bandInfos[1].syncWith = 0;");
 out.println ("            bandInfos[1].highlight = true;");
 out.println ("");
 out.println ("            for (var i = 0; i < bandInfos.length; i++) {");
 out.println ("                bandInfos[i].decorators = [");
 out.println ("                    new Timeline.SpanHighlightDecorator({");
 out.println ("                        startDate:  \"" + getFechaInicioMesActual() + "\",");
 out.println ("                        endDate:    \"" + getFechaInicioMesSiguiente() + "\",");
 out.println ("                        color:      \"#AAAACD\", // set color explicitly");
 out.println ("                        opacity:    50,");
 out.println ("                        theme:      theme");
 out.println ("                    })");
 out.println ("                ];");
 out.println ("            }");
 out.println ("tl1 = Timeline.create(document.getElementById(\"tl1\"), bandInfos, Timeline.HORIZONTAL);");
 out.println ("Timeline.loadXML(\"servlet1?time=" + new Date().getTime() + "\", function(xml, url) { eventSource.loadXML(xml, url); });");
 out.println ("}");
 out.println ("</script>");
  • Un tercer servlet que creará la parte HTML que va en el body de la página y que pinta la línea de tiempo.
out.print("<div id=\"body\">");
 out.print("<div style=\"float: rigth; margin-left: 1em; margin-bottom: 1em;\">");
 out.print("<table>");
 out.print("<tr>");
 out.print("<td>");
 out.print("<div id=\"tl1\" class=\"timeline-default\" style=\"width: 600px; height: 200px;\"></div>");
 out.print("</td>");
 out.print("</tr>");
 out.print("</table>");
 out.print("</div>");
 out.print("</div>");
 out.close();

Tendremos que escribir también código en el botón para que al pulsarse, se grabe en la sesión el valor seleccionado en la lista de parámetros, para que pueda ser recogido por el primer servlet.

En la página jspx se incluirá en la cabecera una llamada al servlet2:

 <f:view>
   <afh:html>
     <afh:head title="Mi pagina">
       <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/>
       <f:subview id="timelinehead">
         <jsp:include page="/servlet2"/>
       </f:subview>
     </afh:head>
     <afh:body onload="onLoad();">

En el cuerpo de la página se incluirá una llamada al servlet3:

 <f:verbatim>
   <f:subview id="timelinebody">
     <jsp:include page="/servlet3"/>
   </f:subview>
 </f:verbatim>

La cáscara de plátano

Lo último que hay que hacer es incluir en el mismo directorio que nuestra página JSPX un fichero con el nombre __history__.html que contenga lo siguiente:

<html><body></body></html>

Al parecer, la librería javascript busca en un momento dado este fichero y si no lo encuentra, provoca una exepción como la siguiente:

com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:346)
com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:152)
oracle.adfinternal.view.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:157)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:107)
com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:245)
com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:137)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:214)
com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilterChain.java:65)
oracle.adfinternal.view.faces.webapp.AdfFacesFilterImpl._invokeDoFilter(AdfFacesFilterImpl.java:228)
oracle.adfinternal.view.faces.webapp.AdfFacesFilterImpl._doFilterImpl(AdfFacesFilterImpl.java:197)
oracle.adfinternal.view.faces.webapp.AdfFacesFilterImpl.doFilter(AdfFacesFilterImpl.java:123)
...

septiembre 22, 2009 at 12:37 pm Deja un comentario

Generando un PKCS#7 desde un dispositivo Android

Para el proyecto que nos ocupa era necesario demostrar que es posible generar un fichero PKCS#7 desde un dispositivo Android para, de esa forma, dar por bueno los Android.

Como ya es sabido Android incorpora Dalvik, una máquina virtual pseudo-Java. En mi equipo tenemos experiencia en la generación y validación de ficheros PKCS#7 desde Java mediante el uso de las librerías BouncyCastle, así que la consecución del objetivo era fácil… a priori.

Pues no. Nos encontramos con problemas: al lanzar en modo depuración la aplicación concepto, en la máquina virtual vemos que Davilk no carga muchas clases de BouncyCastle.

Una de las ventajas que tiene Android sobre sus competidores es que se trata de un proyecto Open Source. Esto hace que Android sea transparente: sus virtudes y sus defectos están a la vista. No hay ni trampa ni cartón.

Buceando por el código fuente de Android encontré que bouncycastle es usuado por las librerías de Android como base para SSL. Entonces, cuando Dalvik intentaba cargar nuestras librerías pues entraban en colisión con las ya precargadas en Android.

El objetivo ahora si está al alcance de la mano. Para el test era suficiente renombrar las librerías de BouncyCastle y… voila! fichero PCKS#7 generado y
validado.

¡Objetivo cumplido!

julio 26, 2009 at 12:54 am Deja un comentario

La Oreja de Van Gogh y Carl Sagan

Imagen de Carl Sagan

Imagen de Carl Sagan

Recientemente tuve ocasión de escuchar atentamente la letra de la canción “Europa VII” de La Oreja de Van Gogh y no pude evitar acordarme de algunas de las ideas que Carl Sagan expuso a lo largo de su vida. La referencia a “un diminuto punto azul se pierde en un millón de chispas” me hizo acordarme de “un punto azul pálido”, donde se relativiza todo el drama humano y se le da una visión desde una perspectiva cósmica que lo convierte en algo trivial. Esa idea flota en toda la canción (“es mi planeta a un día luz y una lección de perspectiva“…). También, el alegato pacifista de Sagan en plena guerra fría contra la división del mundo en bloques enfrentados podrían verse de algún modo recordados por esta estrofa: “me quito la bandera de mi traje espacial y escribo en el reverso que soy de la humanidad“.

La canción continúa: “la frágil existencia milagrosa y casual, la vida más pequeña vale mil veces más que la nación

Imagen del video "Europa VII" de la Oreja de Van Gogh

Imagen del video "Europa VII" de la Oreja de Van Gogh

más grande que se invente jamás“. Me recuerda a “La vida es sólo un vistazo momentáneo de las maravillas de este asombroso universo…” y a cómo se nos recordaba en el segundo capítulo de Cosmos (“Una voz en la fuga cósmica”, donde el propio título ya es de por sí revelador), que la vida se debe a una sucesión de casualidades, ensayos y errores de la Naturaleza, que de manera milagrosa, nos han llevado a ser lo que somos, a estar donde estamos y a ser parte de un Universo al que, de forma parcial, podemos comprender.  La fragilidad de la vida de la que habla la canción se plasmó en Cosmos mediante el símbolo de un diente de león, sobre el cual metafóricamente el científico realizó su “viaje personal”.

Ahora voy a ponerme una canción de Julio Iglesias a ver si encuentro alguna relación con los discursos de Obama. Como los dos son negros… 😉

junio 29, 2009 at 3:07 pm 1 comentario

Lluvia de Androids

Imagen de  Android

“It’s raining Androids” reza el lema de la camiseta que con la que amablemente nos obsequiaron en el stand de HTC en el movilforum (por cierto… ¡impresionantes las instalaciones de Telefónica en Distrito C en Madrid!). He encontrado un video en el que HTC anuncia nuevos teléfonos Android para telefónica grabado en el propio movilforum (el muchacho del fondo con pinta de becario es el que nos atendió).

Reconozco que llegué a movilforum con las ideas ya preconcebidas y con las conclusiones casi redactadas: “el iPhone era el aparato ideal para nuestro propósito”. Después de asistir a varias ponencias y de tocar el HTC dream… pues ya no lo tenía tan claro. Ya alguna gente me había advertido que la solución Android era tecnológicamente más avanzada que la solución iPhone. Y así es: basta con buscar por internet para encontrar multitud de comparativas que refrendan en mayor o menor medida este extremo. Sólo hay una cosa en la que el iPhone gana por goleada: la cuidada estética tanto en el hardware como en el software.

Poco después del movilforum se ha celebrado el Google I/O donde Android ha tenido un papel muy relevante. Puedes ver los videos de las sesiones sobre Android. Paralelamente a las sesiones técnicas se han producido multitud de comunicados de diferentes empresas anunciando nuevos productos Android y más cobertura: la lluvia de Androids empieza.

Después del Google I/O le ha tocado el turno al Computex, donde además de anunciarse más teléfonos Android han empezado a anunciarse netbooks también con Android. Paralelamente, en un evento celebrado en Barcelona, Canonical (Ubuntu) animaba a los desarrolladores a crear aplicaciones Android que correrían sobre ubuntu gracias al entorno de ejecución en el que están trabajando. Aprieta la lluvia de Androids.

¿Sueñan los androides con pingüinos eléctricos? En Arts Technica ofrecen una respuesta en el post: Introducción a Android para desarrolladores. Es un buen punto para empezar a conocer Android.

Mis conclusiones: lo que me gusta de Android.

  • Orientado a ofrecer una agradable experiencia de usuario: el interface de usuario es cuidado y moderno.
  • Open Source, transparente: puedes ver sus virtudes y sus defectos. Están ahí, no tienes más que mirar con un poco de detenimiento y lo veras… ¡todo!
  • Alto potencial de crecimiento: ahora mismo se están dando los primero pasos… han aparecido los primeros teléfonos HTC con Android (dream y magic). Dentro de unos meses muchas marcas tendrán su teléfono Android.
  • Es linux, al igual que el iPhone… y yo en linux, como pez en el agua.
  • Es java! bueno… no exactamente. Digamos que es Dalvik, o sea, java al 95%.
  • Es una apuesta de Google… y la apuestas de Google suelen ser apuestas ganadoras.

junio 9, 2009 at 12:27 am Deja un comentario

De paseo con la BIOS

Si tienes una Acer Aspire One, te interesa tener a mano este Blog: macles*. No se quien es el tio o tia que lo escribe, pero tengo claro que conoce el AA1 y conoce Linpus.

Es la segunda vez que me pasa. No tengo muy claro cual es la razón que lo produce pero, como digo, es la segunda vez que la BIOS de mi AA1 se va de paseo. Apago el AA1 después de una sesión de trabajo normal y cuando voy a encenderlo… ¡nada! … ¡nada de nada! … bueno si: el ventilador funcionando, el piloto indicando que el AA1 está encendido y la pantalla en negro. La BIOS se ha ido a dar un paseo.

¿Como se soluciona? pues macles* tiene la respuesta en el post Acer Aspire One BIOS Recovery. Se resume en los siguientes paso:

  1. Descargar la última versión de la BIOS (al día de hoy va por la 3310). En macles* puedes encontrar el enlace de descarga.
  2. Descomprimir el zip.
  3. Copiar a una memoria USB el fichero FLASHIT.EXE y el fichero de la BIOS.
  4. Renombrar el fichero de la BIOS a ZG5IA32.FD (esto es importante).
  5. Poner la memoria USB en el AA1.
  6. Arrancar pulsando las teclas Fn + Esc durante un par de segundos.

El indicador de encendido parpadeará y al cabo de unos instantes se reiniciará el AA1.

Fin. La BIOS ha vuelto a casa.

mayo 10, 2009 at 11:49 pm 1 comentario

Live Fedora 11 en una memoria USB

Faltan pocos días para el lanzamiento de Fedora 11. Mi intención es montar dicha distribución de Linux en mi pequeño Acer Aspire One (AA1) dado que mi AA1 aún tiene instalado el Linpus original y, la verdad, dicha distro se está quedando muy descuidada. Claro que antes de instalar F11 en mi AA1 quiero comprobar que todo funciona adecuadamente. Para ello, he descargado la Preview de F11 (concretamente el spin XFCE) y lo he montado en una memoria USB.

¿Como se hace esto? Pues es muy, muy sencillo, sobre todo si ya tienes instalado Fedora 10 (yo lo tengo instalado en mi ordenador de sobremesa). Las instrucciones para hacerlo están disponibles en el Wiki de Fedora: How to create and use Live USB. No voy a explicar nada sobre el proceso de creación del Live USB ya que en el Wiki de Fedora está perfectamente explicado y no aportaría nada, pero si quiero llamar la atención sobre la posibilidad de hacer persistir la información mediante un overlay.

Este es el comando que yo he utilizado:

livecd-iso-to-disk --overlay-size-mb 2047 F11-Preview-i686-Live-XFCE.iso /dev/sdd1

Quiere decir que mi live USB dispone de 2047 MBytes para hacer persistir la información o los cambios en Fedora 11 más alla del apagado de la máquina. El tamaño máximo que acepta la shell para el overlay es, precisamente, 2047 MBytes.

En cuanto a las pruebas de Fedora 11 sobre AA1… en general va todo bien, pero eso da para otro post.

mayo 10, 2009 at 1:14 am 2 comentarios


Autores