Jan 26

Más de JSTL: core_rt y obtener el locale fijado con fmt:setLocale

Bueno, sigo jugando con JSTL. Un par de cosillas que he descubierto estos días.

JSTL core_rt

En el post anterior mencionaba una posible forma de acceder a las constantes de un bean desde jstl. Otra forma es, en vez de usar el JSTL core, usar el JSTL core_rt, que está pensado para no usar las expresion EL típicas de JSTL core como ${variable}, sino para usar y tener acceso a las mismas variables y expresiones de los scriptlets que van entre <% … %>

Con JSTL core haríamos algo como

<jsp:useBean id="bean" class="com.chuidiang.UnaClase"></jsp:useBean>

<c:out value="${bean.UNA_CONSTANTE}" />

y que requería del método getUNA_CONSTANTE() en el bean UnaClase

Pues bien, otra opción para esto es usar core_rt

<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt"%>

y esto nos permitiría hacer directamente

<c_rt:out value="<%= UnaClase.UNA_CONSTANTE %>"/>

donde hemos podido usar un normalito <%= …. %>

Con core_rt tenemos todos los tags de core, con la diferencia de que usaremos <%= …%> en vez ${ …. }

Obtener el locale fijado con fmt:setLocale

Otro de los grupos de tags de JSTL es para la internacionalización (i18n que dicen ahora, ya que entre la i y la n de "internacionalización" hay 18 letras). Importando la taglib adecuada

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

A partir de ahí tenemos fmt:setBundle para indicar dónde están nuestros ficheros de propiedades con los textos en los distintos idiomas, fmt:message que nos permite mostrar textos al usuario según el idioma seleccionado (por defecto el del navegador) y fmt:setLocale si queremos un idioma distinto del navegador (por ejemplo, para ofrecer al usuario que lo solicita otro idioma distinto). Hay más tag para formateo de fechas y números de acuerdo al idioma elegido.

Pero echo en falta de menos un fmt:getLocale. Si cambiamos el locale con fmt:setLocale, no hay forma simple de saber más adelante cual hemos puesto. Pero sí la hay, un poco rebuscada. Si hacemos este cambio

<fmt:setLocale value="en_UK"/>

el scope por defecto es page y podemos obtener el locale con

<c:out value="${pageScope['javax.servlet.jsp.jstl.fmt.locale.page']}"/>

y si lo cambiamos con scope="session" para que afecte a todas las páginas en la sesión

<fmt:setLocale value="en_UK" scope="session"/>

se puede obtener más adelante o en otra página con

c:out value="${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}"/>

¿Y para qué es útil esto?. Pues no lo tengo claro, pero comento para qué me ha hecho falta. La aplicación también tiene javascript y también tiene textos en los javascript (por ejemplo, en las ventanas confirm() o alert() antes de borrar algo). Para internacionalizar javascript suele ser necesario incluir algún fichero .js con los textos. También es habitual que haya un fichero distinto para cada lenguaje, por ejemplo es.js, en.js, etc. Y claro, no vamos a incluir todos estos ficheros en nuestra página, sólo deberíamos incluir el necesario para la visualización concreta que estemos haciendo. Pues una forma de conseguirlo es hacer la inclusión de esta manera

<script src=’path/<c:out value="es.js"/>’  …. ></script>

por supuesto, sin poner es.js a piñón fijo, sino obteniéndolo con el pequeño chorizo anterior. Quedaría tan feo como esto

<script src=’path/<c:out value="${sessionScope['javax.servlet.jsp.jstl.fmt.locale.session']}.js"/>’ ….></script>

 Eso sí, tampoco es tan simple, ya que si no hemos hecho un fmt:setLocale, ese valor no existe y es null. Tenemos que recoger entonces el locale de ${pageContext.request.locale}, que es donde está el locale del navegador. Así que nos tocará hacer un if ….

Jan 17

Constantes en los beans y JSTL

A veces, en una aplicación web con JSTL nos vendría bien tener una constante definida en uno de los beans de java, estilo

public class UnaClase {
   public static final String UNA_CONSTANTE = "algo";
   …
}

y luego poder llamarla desde JSTL con algo como

<jsp:useBean id="bean" class="com.chuidiang.UnaClase"></jsp:useBean>

<c:out value="${bean.UNA_CONSTANTE}" />

Desgraciadamente, eso no funciona. JSTL presupone que UNA_CONSTANTE es un atributo del bean y va a convertir ese ${bean.UNA_CONSTANTE} en una llamada al método bean.getUNA_CONSTANTE() que no existe.

La solución es fácil, basta con crear un método getUNA_CONSTANTE() en el bean que devuelva el valor de la constante. Unicamente tenemos que tener en cuenta que ese método no puede ser static, puesto que si no JSTL tampoco lo llamará (por debajo, probablemente usa la introspección de java y no busca métodos estáticos). El bean quedaría así

public class UnaClase {
   public static final String UNA_CONSTANTE = "algo";

   public String getUNA_CONSTANTE () {
      return UnaClase.UNA_CONSTANTE;
   }

}

que sí funciona como esperamos.

Jan 14

El WebappClassLoader y ContextClassLoader en Tomcat/Liferay

En el desarrollo nos hemos encontrado con un problema curioso. Estamos desarrollando un portlet con Liferay y necesitamos desde él hacer llamadas AJAX que actualicen parte del portlet sin refrescar la página. Se nos ha ocurrido, en la parte del servidor, hacer un jsp que sería el que reciba estas llamadas desde la parte de javascript, digamos un funcion.jsp. En esa funcion.jsp usamos clases de nuestra parte del servidor del portlet, en concreto, usamos los jar que hay en el WEB-INF/lib de ese portlet.

Pues bien, el problema que se nos ha presentado es que aunque todo parece ir bien tanto en el funcion.jsp como en las clases que se van llamando, hay un sitio concreto en el que hay un problema. Esas clases crean un cliente de web service con Apache CXF para conseguir datos en otros servidores y en la creación de ese cliente nos salta el problema, una excepción fea

ClassCastException: com.sun.xml.ws.client.sei.SEIStub cannot be cast to org.apache.cxf.frontend.ClientProxy [java] at org.apache.cxf.frontend.ClientProxy.

A poco que se hurge con google, encontramos que la versión 6 de java viene con un proveedor por defecto para web services. Java proporciona mecanismos para cambiar ese proveedor por defecto por el que queramos, en concreto y entre otras opciones, basta con poner en el classpath el fichero META-INF/services/javax.xml.ws.spi con una única línea de texto que sería la clase proveedor de web service que queramos uar,  en mi caso, la de apache cxf. La excepción surge si cuando java busca el proveedor no lo encuentra, poniendo entonces el suyo por defecto, que no es compatible con Apache CXF.

Normalmente no debemos preocuparnos de esto, el jar cxf-rt-frontend-jaxws.jar de apache cxf contiene ese fichero debidamente configurado, por lo que si este jar está en el classpath, no debería haber problemas.

¿Por qué entonces surge el problema cuando llamo al funcion.jsp si este jar está en el WEB-INF/lib?. Pues tras varios días de pruebas, google y más pruebas, encontramos que nuestras clases usan por defecto el WebappClassLoader que les proporciona tomcat, por lo que todos los jar en WEB-INF/lib de nuestro portlet están disponibles, pero java, cuando busca el proveedor de servicios, usa Thread.currentThread().getContextClassLoader() que NO le devuelve el WebappClassLoader, sino el de la propia aplicación de Tomcat, por lo que las clases de nuestra aplicación no están disponibles.

Si experimentamos y hurgamos un poco más, vemos que Tomcat, cuando va a llamar a algo de nuestra aplicación web, nos cambia ese ContextClassLoader haciendo algo como

Thread.currentThread.setContextClassLoader(elWebappContextClassLoaderCorrespondiente);

y luego, cuando nuestra aplicación termina de hacer lo que tenga que hacer, Tomcat restaura el ContextClassLoader por el de defecto.

El problema que tenemos entonces es que cuando se llama a nuestra funcion.jsp, no se está cambiando ese ClassLoader. Ahora, sabiendo el problema, la solución debería ser fácil.

La primera y más inmediata es que nosotros mismos, antes de crear el cliente web service, cambiamos ese ContextClassLoader y luego lo restauramos, algo similar a lo que hace Tomcat. Esta opción no me gusta porque no me gusta jugar con los ClassLoader sin saber a ciencia cierta qué hago, y sobre todo porque Tomcat debería cambiarnos el ClassLoader y no lo hace, lo que implica que algo tenemos mal configurado.

Como estamos con liferay y llamamos a funcion.jsp con una URL directa, no a través del portlet liferay, imagino que ahí vienen los problemas. Así que toca "investigar" un poco a ver cómo conseguir que liferay/tomcat consideren funcion.jsp como parte del webapp o portlet y le cambien el classloader al Thread dichoso.

 

Jan 10

Un eBook

wibook 650tEstas navidades a los reyes les ha dado por traer eBooks. A mi madre le han traído uno, el Kindle de Amazon. A mi me ha tocado el wibook del Corte Inglés. Y he jugado un poco con ambos, pero sin matarme, tampoco soy de los que andan mirando al detalle estos chismes, sólo lo quiero para leer. Y así, en un poco de jugar, ¿qué diferencias veo entre uno y otro?.

La más evidente es la pantalla táctil del wibook. La del Kindle no lo es. No tiene especial importancia, ya que entre pasar página apretando un botón o arrastrando el dedo sobre la pantalla no hay demasiada diferencia. Sí se nota si alguien es de los que se dedica a escribir notas. Es más cómodo un teclado dibujado sobre una pantalla táctil que un teclado sobre una pantalla en la que no puedes tocar y la forma de pulsar teclas es usar las flechitas para seleccionar la tecla y luego pulsar el botón de en medio para hacer click en la tecla. También es más cómodo para teclear un número de página a la que quieres ir.

Una pega para el wibook que sí me molesta un poco más. El encendido del Kindle es inmediato y te muestra la última página que tuvieras abierta al apagarlo. El wibook tarda un poco en encenderse ¿unos 20 segundos? y siempre te muestra el menú de inicio, por lo que inmediatamente después de encenderlo debes pulsar en la pantalla para abrir el libro que estás leyendo (sólo una pulsación). Teniendo en cuenta que pasada la novedad del eBook el 99% de las veces lo encenderemos para leer, se agradece más el encendido rápido y directo en la página a leer, como hace el Kindle.

En cuanto al tema reflejos…. simplemente un detalle que yo no sabía. Casi todos los eBooks dicen tener pantalla anti-reflejos. Bueno, eso hay que entenderlo. Se refieren a que puedes leer con ellos en la calle con luz natural. En general los displays de los dispositivos como móviles o cámaras de fotos se ven bastante mal si les da la luz del sol más o menos directa. No lo he probado pero en los eBooks en principio esto no pasa y es lo que quiere decir anti-reflejos. Sin embargo, si lees en casa con una lámpara… hay que orientar el eBook de forma adecuada para que la lámpara no refleje en la pantalla, que sí refleja. No he comparado ambos en detalle, pero me da la impresión de que el kindle refleja algo menos.

En cualquier caso, estoy contento con el regalo (un eBook), puesto que soy lector habitual, (sí caen alrededor de una decena de novelas al año), me gusta leer en las cafeterías (y algunos libros pesan más de la cuenta) y tengo una habitación llena de estanterías llenas de libros en varias filas y montones.

Dec 15

Clases y herencia con javascript

 Por la necesidad de organizar un poco el código de javascript, que va creciendo y creciendo de forma desordenada y desmesurada en nuestro proyecto, me he puesto a mirar un poco el tema de objetos y herencias, también como organizar esas clases en lo que en java se llaman paquetes, no sé si en javascript se llaman namespaces, o ni siquiera existe nombre para eso.

Me ha llamado la atención que las clases realmente son las funciones. Cualquier función que declaremos en javascript es una clase y se puede hacer un new de ella. La función en sí misma se convierte en el constructor de la clase y las "cosas" que definamos en esa función como this.cosa=…. se convierte en atributo o método de esa clase, según sea una variable u otra función.

La herencia es un poco rara, sobre todo cuando buscamos en internet en que hay 49 formas de hacerla y alguna más. Al final, lo más sencillo y mínimo imprescindible es hacer algo como ClaseHija.prototype = new ClasePadre; Ya está la herencia hecha.

Si el constructor Padre tiene parámetros (la función Padre tiene parámetros), podemos llamarla desde el constructor del Hijo (la función Hijo) usando call() tal que así Padre.call(this,parametros), esa sería la forma de que el constructor hijo llame al padre pasándole cosas.

Finalmente, para agrupar las clases en "paquetes" o como quiera que se llame en javascript, basta con hacer el típico 

paquete = {
   Padre : function(…) {….},
   Hijo : function(…) {…}
}

a = new paquete.Hijo;

En fin, lenguaje demoníaco por un lado, pero me está gustando por otro. Mas detalles de lo aprendido en la chuwiki.

Dec 11

Gráficas de ecuaciones con google

 Curioso, si en google buscas una ecuación como y=sin(x), aparece el gráfico de la misma. Se puede desplazar, hacer zoom con la rueda del ratón o con los botones, etc, etc.

vía Oh my tec !

Dec 10

Mezclando tecnologías : JSF y jQuery

Hace un tiempo estuve leyendo el tutorial de la antes SUN sobre JSF y estos días estoy leyendo sobre jQuery. Por aquello de jugar un poco con ambas cosas me dije: voy a hacer un proyectito. Una lista de tareas web con base de datos y JSF, pero que se puedan ordenar arrastrándolas con el ratón usando sortable de jQuery. Por supuesto, cada vez que se arrastra una fila de la lista y se coloca en otra posición, debería almacenarse su nueva posición en base de datos.

Pues nada, me pongo a ello. Con JSF me hago toda la parte de base de datos, lista de tarear y botones para editar, borrar y crear.

Ahora me pongo con la parte de jQuery. Lo de hacer la tabla "sortable" y arrastrar las filas de un lado para otro sin ningún problema. Toca hacer la persistencia…. y ahí es donde han empezado mis problemas.

Con jQuery puedo enterarme cuándo se arrastra una fila y hacer una pequeña llamada jQuery.ajax() para indicarle al servidor el nuevo orden y que lo guarde en base de datos. La primera "pega"es que no hay forma fácil de llamar desde jQuery a un managed bean de JSF.La solución pasa por hacerse un JSP normalito o Servlet para recoger esas llamadas jQuery.ajax(). Ese JSP sí puede intentar conseguir el ManagedBean de JSF y hacer la llamada correspondiente.

La segunda pega de momento es más insalvable de una forma sencilla. Con jQuery y sortable() puedo obtener el orden de los elementos por su id del tag html. Es decir, si uso un <table> y quiero ordenar los <tr>, cada <tr> debe tener un id <tr id="algo">….</tr>. En la llamada a jQuery.ajax() se pasaría como parámetro esa lista de id de los <tr> en el orden en que están en pantalla. Y este id debería ser el id de la Tarea en esa fila, de esta forma cuando esa lista de id llegue al servidor, este sabrá el orden de las tareas.

Pero JSF, con su tag DataTable usa columnas y no pone ningún id a los <tr>. Y no hay forma de ponérselo de ninguna forma fácil. Tampoco con javascript/jQuery se puede poner a posteriori, porque jQuery no puede acceder al ManagedBean que ha generado la fila y por tanto a su id. Posiblemente se puede poner una columna oculta con los id de tarea y así jQuery podría poner el id al <tr> según el valor de la columna oculta… pero se me hace un poco "artificioso".

Y ahí me he atascado. JSF no pone id a los <tr> ni forma fácil de hacerlo. JQuery no puede acceder a los ManagedBean para poner ese id a posteriori.

Resumiendo, me hace la impresión de que cada tecnología sirve para lo que sirve y no siempre es fácil usar varias de ellas a la vez.

Dec 08

Jugando con jQuery

Ahora que me ha empezado a tocar a hacer aplicaciones web, hemos empezado a usar jQuery. En los proyectos había hecho algo, pero siempre por encima y sin saber muy bien qué estaba haciendo. Lo típico de buscar en la documentación o en google, encontrar el trozo de código que hace lo que tú quieres, copy-paste y arreglarlo hasta que funcione.

Pero ahora me he puesto a jugar con jQuery un poco más en serio y la verdad es que me ha gustado lo que he visto.

Aunque parece raro al principio, sobre todo porque no tengo ni idea de javascript, te acostumbras rápido a usarlo. Es muy sencillo y funciona bien, además de ser bastante potente.

Tenemos por un lado su funcionalidad "básica", que permite fácilmente buscar elementos dentro de la página web, cambiar cosas, etc, etc. Y me ha gustado especialmente la sencillez con que se pueden hacer llamadas tipo AJAX y lo fácil que se puede leer la respuesta si viene en formato JSON. De hecho, jQuery te transforma automáticamente esa respuesta JSON en un objeto javascript con los atributos y valores correspondientes al JSON. No sé yo el XML, cada vez me da más "yuyu", incluso desde java, nunca es fácil de leer y siempre tienes que liar el código con clases Document, y Node, y buscando Childs …. 

Para la parte de Drag and Drop, por supuesto tenemos lo básico para hacer lo que queramos, pero lo más "molón" es sortable(), que te da directamente una lista que se puede ordenar arrastrando los items con el ratón sin más necesidad que una línea de código javascript. Se puede incluso hacer varias listas y permitir que los elementos se puedan pasar de una a otra … y sólo requiere una línea de javascript por cada lista.

Tenemos también en jQuery una serie de "Widgets" opcionales, como diálogos, pestañas, acordeones, fechas, etc, etc que también son sencillos de usar. La "pega" es que para que salga algo decente requieren unos CSS más o menos complejos. Por lo que casi no queda más remedio que bajarse alguno de algún sitio ….. pero me ha llamado mucho la atención themeroller. Estos de jQuery lo tienen todo pensado y entrando en la página de themeroller podemos definir con el navegador nuestro propio CSS, viendo cómo queda sobre la marcha según vamos tocando, y luego bajarnos el tema completo junto con las librerías de jQuery (la básica y la de los Widgets).

En fin, me ha gustado mucho todo lo que he visto hasta ahora. Sé que solo he ido haciendo unas pruebas básicas para ir aprendiendo y que en una aplicación real puede haber más "enrevesamiento" del previsto.

Nov 30

Botón google +

Llevaba un tiempo viendo cómo prolifera en los sitios web el botón google +1 y quise ponerlo en mi sitio. Buscando cómo ponerlo encontraba cosas que no me acababan de hacer gracia. Hoy he buscado un poco más en serio, he encontrado cómo ponerlo, por supuesto, en el sitio oficial 

Así que ya está, este blog, la chuwiki y el sitio principal tienen todos su botoncito. Ahora a ver qué pasa.

ACTUALIZACIÓN. También he puesto hoy el botón de "twitear", pero me da la impresión de que no va muy bien. Pinchando en el número de "twits", te va a la página de twiter y te muestra los "twits" correspondientes. Pues bien, en el momento de mirar esto, uno de los posts dice 3 twits y pinchando, twiter te muestra sólo dos twits y uno de ellos no tiene nada que ver con el tema. Me recuerda al viejo chiste que dice "Los cuatro contienentes del mundo son tres, Europa y del otro no me acuerdo".

El botón de twiter se saca de aquí http://twitter.com/about/resources/tweetbutton

Nov 27

Google analytics en tiempo real

Hace tiempo que tengo google analytics en mis sitios web. Antes lo miraba con frecuencia, vigilaba las visitas a ver si subían o bajaban, jugaba a ver si había visitantes de países/ciudades exóticas, etc, etc. Pero también hace mucho tiempo que dejé de mirarlo, llega un momento que aburre y si hay muchas o pocas visitas no es más que un dato curioso que no me preocupa en exceso.

Pero ayer se me ocurrió entrar…. y he visto que han cambiado la interfaz que han puesto una cosa que se llama "tiempo real beta". Otra curiosidad más. Muestra en tiempo real las visitas que hay en tu sitio. Unos gráficos con tiempo en el eje X se van desplazando en tiempo real e indicando el número de visitas, un listado de páginas que están siendo vistas y que van cambiando, un mapa en el que ves de dónde vienen los visitantes que también cambia … en fin, curioso

En el vídeo, sobre el minuto 1:15