Archive for the ‘Programación’ Category

h1

Pasar un método como parámetro a un composite component de JSF

27 agosto 2010

En una aplicación para el trabajo (aún no he conseguido escapar de las garras de JSF 😦 ) necesitaba que, cuando un usuario fuese a salir de una página de edición, se le notificase mediante un cuadro de diálogo que perdería los cambios sin guardar. Como había bastantes salidas posibles (botones, elementos de menú…) decidí crear el diálogo en un composite component. Por si a alguien le interesa, para el diálogo en sí utilicé la biblioteca PrimeFaces 2.1, basada en jQuery UI.

Evidentemente, cada salida tenía un destino diferente: en el caso de los elementos de menú cada uno dirigía a una parte distinta de la aplicación. Por ello, necesitaba pasar como parámetro del componente la acción a ejecutar.
Sin embargo, esto no es que esté precisamente documentado de manera muy espléndida en ninguna parte, pero encontré la solución gracias a un tutorial en IBM DeveloperWorks.

Debemos definir nuestro componente al menos con el contenido del siguiente cuadro, donde he simplificado mi situación (en lugar de un diálogo de confirmación solo hay un botón) para que se vea de forma más obvia la solución 🙂

<cc:interface>
  <cc:attribute name="actionMethod" 
                required="true"
                method-signature="java.lang.String action()" />
</cc:interface>
<cc:implementation>
  <h:commandButton value="¡Púlsame!"
                action="#{cc.attrs.actionMethod}" />
</cc:implementation>

En la interfaz se debe definir un atributo que evalúe a un método; lo he llamado “actionMethod”. Importante: En el atributo method-signature se debe proporcionar la declaración de tipos completa, como en java.lang.String.

Con esto ya podemos invocar el componente desde cualquier página con:

<lib:componente actionMethod="#{controlador.accion}" />
Anuncios
h1

Incluir JAR propio en un repositorio Maven local

24 marzo 2010

Una de las principales ventajas de Maven es que gestiona las dependencias de los proyectos descargándolas a un repositorio local la primera vez que se necesiten. Sin embargo, posiblemente tengamos que incluir algunas a mano porque no estén disponibles en los repositorios “oficiales”, como me ocurrió con Qt Jambi (editado: hoy he descubierto que hay un repositorio independiente en Sourceforge para la versión Community). Después de dar vueltas buscando una solución, resultó estar en las FAQ de Maven 🙂

Para incluir un artefacto debemos ejecutar una orden donde indicar cuál es el archivo a subir, su groupId, artifactId, versión, tipo de empaquetado y si debe generar el POM (no veo ningún motivo para no hacerlo), utilizando una orden como la siguiente. Nota: Si tenemos el ejecutable de Maven en el PATH podemos colocarnos en la carpeta donde se encuentre el artefacto para no tener que escribir toda su ruta.

mvn install:install-file -Dfile=qtjambi-4.5.0_01.jar -DgroupId=qtjambi -DartifactId=qtjambi -Dversion=4.5.0_01 -Dpackaging=jar -DgeneratePom=true

En este caso concreto el groupId y el artifactId coinciden porque me pareció más coherente, ya que se trata del JAR principal para cualquier aplicación que utilice Qt Jambi. Si también fuésemos a incluir las distribuciones para Windows, Mac y Linux podríamos hacerlo dentro del mismo groupId pero con distinto artifactId, como en las siguientes órdenes:

mvn install:install-file -Dfile=qtjambi-win32-msvc2005-4.5.0_01.jar -DgroupId=qtjambi -DartifactId=qtjambi-win -Dversion=4.5.0_01 -Dpackaging=jar -DgeneratePom=true
mvn install:install-file -Dfile=qtjambi-macosx-gcc-4.5.0_01.jar -DgroupId=qtjambi -DartifactId=qtjambi-mac -Dversion=4.5.0_01 -Dpackaging=jar -DgeneratePom=true
mvn install:install-file -Dfile=qtjambi-linux32-gcc-4.5.0_01.jar -DgroupId=qtjambi -DartifactId=qtjambi-linux -Dversion=4.5.0_01 -Dpackaging=jar -DgeneratePom=true
Y con esto tenemos cuatro nuevos JAR en nuestro repositorio local, listos para ser utilizados desde cualquier proyecto Maven 😀

h1

Illegal mix of collations en procedimiento almacenado de MySQL

23 marzo 2010

En el trabajo he tenido que modificar el modelo de una base de datos MySQL para un proyecto ya casi terminado (benditos lusers que no saben cómo hacen lo que hacen), por lo que creé un par de procedimientos almacenados. En mi equipo funcionaban perfectamente, pero al probarlo en otro no hacía más que mostrar el error:

ERROR 1267 (HY000): Illegal mix of collations (utf8_spanish_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='

El único punto del procedimiento donde podía ocurrir era en un where donde se comparaban dos longtext:

select id into errorid from errortecnico
where mensaje = errormensaje

Buscando y buscando encontré la inspiración en el blog de Pablo Viquez, un desarrollador de Costa Rica, con la única diferencia de que su problema ocurría con la codificación latin1.

La solución es convertir la parte del where que causa problemas a la collation (dentro de una codificación, la ordenación de caracteres) que nosotros usamos mediante la sentencia convert, que en mi caso quedaría tal que así:

select id into errorid from errortecnico where mensaje
= CONVERT(errormensaje using utf8) collate utf8_spanish_ci

Con esto, MySQL convertirá automáticamente el dato que interpretaba como utf8_general_ci a utf8_spanish_ci.

h1

Limitaciones de la API Criteria de Hibernate

19 marzo 2010

En el trabajo estoy utilizando la API Criteria para desarrollar un generador de informes, porque permite componer consultas dinámicamente sin tener que concatenar asquerosamente un montón de cadenas de texto. Por desgracia, aún tiene varias limitaciones que no están presentes si utilizamos HQL y que la deslucen un poco.

Lo peor de todo es que descubrirlas puede llevar bastante tiempo, así que por si Google indexa este post de manera que salga en alguna de las primeras entradas, al menos le habrá ahorrado tiempo a alguien xD Las limitaciones que he descubierto hasta ahora son:

  • Cruzar varias veces con la misma tabla (aunque a cada join se le asigne un alias distinto).
  • Restricciones/proyecciones con atributos multivaluados, representados mediante una CollectionOfElements. Para la versión 3.5.0 parece posible que al menos la primera parte del problema se solucione gracias a un parche.
h1

UnsupportedOperationException en array construido con Arrays.asList

26 febrero 2010

Si se intenta ejecutar un método add, remove, etc., sobre una lista construida mediante Arrays.asList se obtiene una UnsupportedOperationException. El motivo es que dicho método no crea una lista dinámica real (como sería un ArrayList) sino una vista para el array. Al seguir usando el mismo objeto que teníamos, por tanto, no se puede redimensionar.

La solución a este problema sería emplear un código como el siguiente para construir una lista dinámica real:

List lista = new ArrayList(Arrays.asList(array));

Fuente: Raja’s Weblog

h1

Encriptar la contraseña de conexión en hibernate.cfg.xml

5 febrero 2010

Por defecto, en el fichero de configuración de Hibernate se muestran en texto plano todos los datos de conexión, lo que evidentemente no resulta muy seguro en cuanto lo ponemos a disposición de los usuarios. Para encriptarlos de manera sencilla podemos utilizar la biblioteca Jasypt (Java Simplified Encryption), que también nos permite encriptar el contenido de la base de datos, aunque eso queda fuera del alcance de este post 🙂

En este caso, supongamos que solo vamos a encriptar la contraseña. Lo primero es generar este valor a partir de una clave mediante uno de los scripts BAT o SH que se incluyen en la distribución. Ejecutamos la orden encrypt.bat input=contraseña_a_encriptar password=clave_del_algoritmo y nos devolverá un resultado como el siguiente:

----ENVIRONMENT-----------------
Runtime: Sun Microsystems Inc. Java HotSpot(TM) Client VM 14.2-b01
----ARGUMENTS-------------------
input: mipass
password: foobar
----OUTPUT----------------------
j1BNruKrxJ9xy9u8e1GtBw==

El valor de salida será el que se escriba en el fichero hibernate.cfg.xml, pero antes nos quedan cosas por hacer. En el fichero donde esté mapeada la base de datos (en caso de usar anotaciones habrá que crear uno nuevo) incluimos la declaración del tipo del cifrador:

<hibernate-mapping>
      <typedef name="encrypted"
      class="org.jasypt.hibernate.type.EncryptedStringType">
            <param name="encryptorRegisteredName">
                  hibernateEncryptor</param>
      </typedef>
</hibernate-mapping>

En la clase donde se cree la SessionFactory de Hibernate (lo habitual es utilizar una llamada HibernateUtil) se asocia esta al cifrador antes declarado:

config = new AnnotationConfiguration().configure();

PBEStringEncryptor encryptor =
      new StandardPBEStringEncryptor();
// La clave se puede obtener consultar en web,
// en una variable del programa o de entorno...
encryptor.setPassword("foobar");
HibernatePBEEncryptorRegistry registry =
      HibernatePBEEncryptorRegistry.getInstance();

// Asignar el mismo nombre que en hibernate-mapping
registry.registerPBEStringEncryptor(
      "hibernateEncryptor", encryptor);

sessionFactory = config.buildSessionFactory();

Y ya es hora de tocar el fichero de configuración de Hibernate, añadiendo las siguientes líneas. Es importante escribir la contraseña encriptada entre paréntesis porque es el formato que utiliza Jasypt para diferenciar las cadenas encriptadas de las que viajan en plano.

<!-- Proveedor más simple de conexión encriptada,
también existe uno sobre C3P0 -->
<property name="connection.provider_class">
      org.jasypt.hibernate.connectionprovider.EncryptedPasswordDriverManagerConnectionProvider
</property>
<property name="connection.encryptor_registered_name">
      hibernateEncryptor
</property>
<property name="connection.password">
      ENC(j1BNruKrxJ9xy9u8e1GtBw==)
</property>

<!-- Fichero con el hibernate-mapping -->
<mapping resource="mapping.xml" />

Y con estos pocos pasos habremos mejorado un poquito la seguridad de nuestra aplicación 😀