Etiqueta: jsf

Por fin un estándar con el que entretejer nuestras aplicaciones.

25 oct 2009

Recientemente se ha liberado la primera versión estable de Weld, la implementación de referencia de Web Beans (Java Context and Dependenty Injection - JSR 299). Y aunque puede parecer una liberación cualquiera, en este caso estamos ante un evento realmente importante para el mundillo Java.

¿Por qué es importante esta liberación?

  • Por fin tenemos un estándar Java para la inyección, publicación, localización y búsqueda de componentes.
  • Promete una mejor orquestación entre componentes JEE, evitando los típicos problemas de interoperabilidad entre Beans Spring, componentes Seam, Wicket, JSF, EL, etc..)
  • Un remplazo estándar a las diferentes soluciones de inyección e IoC como Spring IoC, el prometedor Google Guice o el muy utilizado por nosotros Jboss Seam annotations.
  • Fin del infierno XML, definiendo un mecanismo estándar independiente de ficheros de definición XML, que junto con JSF 2.0, Servlet 3.0, JPA, Jax-ws, etc… simplifican el desarrollo JEE.

¿Consecuencias para la industria a medio plazo?

  • Es demasiado pronto para saberlo, pero…
    ¿Quizás el fin de la guerra de frameworks se inyección?…. (Google Guice vs Spring vs Jboss Seam). Consiguiendo un efecto similar al que consiguió JPA/JDO estandarizando el acceso a datos.
  • Por fin una especificación JEE con la que construir aplicaciones complejas de forma sencilla.
  • En un momento en el que muchas organizaciones están intentando estandarizar sus desarrollos, llegando incluso a restringir o imponer las tecnologías utilizadas, la preselección de implementaciones como Spring IoC o Seam carecerá de sentido. Siendo mucho más coherente la recomendación de estándares en lugar de restringir la evolución natural de la tecnología y la sana competición entre sus diferentes implementaciones.

¿Consecuencia para nosotros?

  • Ninguna…. Gracias a nuestra apuesta por Jboss Seam (desde hace ya unos años), esta especificación se encontraba ya en nuestra hoja de ruta antes incluso de que fuese un Draft, por lo que para nosotros será suficiente con una mínima adaptación al estándar.
  • La implementación es estable, la especificación muy bien pensada, y en las pruebas que hemos realizado con la beta, ha demostrado que consigue simplificar los desarrollos y hacer más comprensible el “oscuro arte de la inyección de componentes”.
  • En breve empezaremos a usarla en algún proyecto piloto (que pueda asumir el riesgo de I+D asociado), analizaremos en detalle los posibles problemas que puedan surgir, y si todo se comporta como promete a mediados de 2010 empezaremos a usar la nueva especificación en nuestros proyectos Java.

¿Defectos?

  • Llega demasiado tarde. Otros frameworks llevan, aunque de una forma mucho menos limpia,  ofreciendo algo similar desde hace ya mucho tiempo.
  • Todavía no conocemos sus defectos. Y eso es un gran problema ya que hasta que no conozcamos sus problemáticas asociadas no será seguro su uso en proyectos de envergadura.
  • Esperemos que en la huida del infierno de los ficheros de configuración XML, no nos metamos en  las tinieblas del uso de inyección e IoC para todo. Ya que una aplicación con una gran cantidad de componentes, comportamientos o atributos que dependen de la inyección hace muy complicada la comprensión de su funcionamiento.

En definitiva, todo indica que estamos antes una de las piezas clave del próximo JEE 6.

Implementando un flujo de firmas en nuestro workflow

03 nov 2008

A continuación vamos a explicar cómo aprovechar las bondades de tres componentes habituales en nuestros desarrollos para implementar un sencillo flujo de firma de formularios.

Los jugadores son:

  1. Jbpm 3.2 como motor de workflow.
  2. Formula 2 como motor de formularios.
  3. Viafirma 1.3.5 como motor de firma digital.

La aplicación que los implementa está desarrollada con Seam + JSF + JPA.

La Descripción

Básicamente el requisito era el siguiente: un formulario completado por un usuario entraba en un flujo de transiciones en el que distintos departamentos y/o personas tenían que ir aprobándolo con su firma digital.

La solución tradicional con la que contábamos se basaba en recuperar los datos del primer formulario, y en la transición adecuada los mostrábamos para que el firmante pudiera comprobar los datos (tareas).

Esto implicaba un esfuerzo en la redendirización nuevamente de los datos facilitados por el usuario, por lo que decidimos aprovechar las características de los componentes usados para simplicarlo todo.

Solución

Formula2 permite la identificación de los campos creados en el formulario. De esta manera nuestra solución consisitirá en identificar un mismo nombre de campo dentro de un mismo ProcessId.

Una vez asegurado en nuestro proceso esta identificación de campos, ahora toca el turno de Formula2; duplicaremos el formulario original, y modificaremos todos sus campos al tipo ReadOnly, de manera que el firmante no pueda modificar los datos mostrados en el formulario inicial.


Copiar un formulario en Formula2

Opcionalmente, a esta copia del formulario se le podrán añadir campos adicionales, como por ejemplo, un campo de observaciones o bien otros campos para informar valores necesarios en la siguiente transición.

Esta tarea de modificar cada campo de un formulario podría resultar algo engorrosa, pero solo habrá que hacerlo una vez, ya que la primera copia con todos sus campos “ReadOnly” nos serviría  de base para las sucesivas copias que necesitemos, y para estas copias ya no será necesario modificar la propiedad de sus campos.

Modificar propiedad campo

Resultado

A medida que el diseño del flujo (process-definition) va ejecutando las tareas e invocando los distintos formularios, los actores propietarios de dichas tareas van firmando con su certificado digital los formularios.

El proceso de firma es delegado a nuestro al motor de firma VIAFIRMA. Cuando éste completa la transacción de firma, devuelve todos los datos necesarios a nuestro sistema. En este caso, Jbpm interpreta estos datos de firma como variables del proceso, añadiéndolos como un dato más de la transición.

Como valor agregado, estos datos de firma y los contenidos en el formulario son indexados mediante Lucene (implementando openSearch), y de esta forma ofrecemos al usuario la posibilidad de buscar su proceso por el código de firma que se le informó.

Histórico del Proceso

Tras el proceso de firma, se le muestra al usuario una pantalla de recibo, donde se le accede a toda la información del proceso con las distintas opciones:

  • Descarga del formulario que fue firmado.
  • Descarga del comprobante de firma, con los datos del firmante y de la transacción (fecha, hora y certificado usado).
  • Id. de las tarea y proceso.
  • Link permanente a su proceso.
  • Todo ello apoyado con imágenes bidimensionales como el Qr-Code con el resumen de la firma y el BarCode con el código de la firma.

Justificante de Firma

Posibles Conflictos

Seguro que a alguno ya se le ha pasado por la cabeza un posible conflicto:

¿Qué ocurre si para un mismo ProcessId se ven involucrados 2 formularios que no son copias el uno del otro, pero el identificador que le pusimos al campo es el mismo, por ejemplo ID_PROFESOR?

  • si el segundo formulario NO es una copia del primero, pero tiene un campo con el mismo Id., efectivamente nuestro proceso hará que este segundo formulario se renderice con el valor introducido para ese campo en el primer formulario. Pero, al no tratarse de una copia, el campo no será del tipo ReadOnly (o no debiera), por lo que el valor podría ser modificado por el usuario.
  • La solución a este tipo de conflictos en nuestro caso: anteponer un identificador del formulario a modo de prefijo en el identificador del campo. Por ejemplo: FRM_9_ID_PROFESOR.

Resumen

Gracias a la funcionalidad de Formula2 para identificar los campos y duplicar formularios conseguiremos una sencilla implementación de un ESCRITORIO DE FIRMA.

  • Nos ahorramos construir N formularios.
  • Nos ahorramos la lógica para recuperar y renderizar los datos asociados al formulario original y que necesitamos ir mostrando a cada firmante.

Sun’s RI for JSF vs MyFaces

21 ene 2008

Época de despedidas, hoy le toca el turno a MyFaces

Después de más de dos años utilizando la implementación Apache Myfaces JSF, ha llegado el momento de las despedidas, en adelante todos nuestros proyectos se pasan a la implementación JSF 1.2 de Sun. No existe un motivo principal, pero si muchos pequeños problemas que finalmente nos han hecho decidirnos por la migración. Sin intención de entrar en detalle, estas son las motivaciones principales:

- En el momento de tomar la decisión, la implementación de Sun de la especificación 1.2 era mucho mas madura que la de Myfaces. En las pruebas realizadas pudimos comprobar que el numero de bugs es mucho mayor en la implementación Myfaces. En general Sun’s RI es una implementación mucho mas pulida.

- El número de incompatibilidades que hemos sufrido al migrar de la especificación 1.1 a 1.2 ha sido mucho menor con la implementación de Sun.

- Es posible seguir utilizando las librerías Tomahawk  con la implementación de Sun.

- La implementación de Sun parece ofrecer mejor rendimiento que la implementación de Myfaces.

- La integración con Seam es mucho mas sencilla utilizando la implementación de Sun.

- Gracias a la filosofía una especificación, múltiples implementaciones; el cambio era posible.

Una JSF universal

13 ene 2008

Un ejemplo de como simplificarnos la vida usando nuestras propias annotations.

Por la razon que fuese teniamos que crearnos un numero considerable pero finito de VOs con un numero tendiente a infinito de propiedades. Estos VOs a los que llamaremos FooData1VO, FooData2VO, … FooDataNVO; estos VOs , digo, iban a ser usados en JSFs en los que una lista del mismo FooDataXVO se representaria como una tabla, una tabla que a su vez seria exportable a excel.

Bien, tenemos dos formas de hacerlo. La normal o infernal, y la anotada o elegante y facil.
En la normal, nos creamos N VOs, N Controllers, y N JSFs.
En la version anotada que proponemos aqui necesitamos: N+1 VOs, 1 Controller universal, 1 JSF universal y 1 Annotation.

Lo primero que hacemos es crearnos nuestra anotacion java (annotation).
Para mas informacion sobre que y como y porque, os remito a mis ya viejos articulos Tu primera annotation chipas I y II:
http://xnoccio.com/62-tu-primera-annotation-chispas-i/
http://xnoccio.com/72-tu-primera-annotation-chispas-ii/


package com.viavansi.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
/**
* @author dbejar
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WiseName{
String alias();
}

Este es un caso muy sencillito en el que unicamente le damos un nombre en lenguaje natural a una propiedad. Podriamos como en el caso real en el que desarrollamos esto, añadirle un booleano para distinguir entre propiedades exportables a excel, o un enum para hacer subconjuntos dentro del mismo VO. Pero estoy adelantando cosas…

A continuacion nos creamos una clase padre de nuestros VOs:

package com.viavansi.VO;


import java.lang.reflect.Field;
import com.viavansi.annotation.WiseName;

public abstract class FooDataSuperVO{
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String>getWiseNamedLabels(){
List<String>aliases=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
aliases.add(nombreBonito.alias());
}
return aliases;
}
/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String> getWiseNamedProperties(){
List<String>propNames=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
propNames.add(field.getName());
}
return propNames;
}

No requiere mucha explicacion, si se han leido y entendido mis articulos sobre Annotation. Basicamente con esas dos funciones por reflection obtenemos en una todas las propiedades anotadas, y en la otra el valor de la propiedad alias en esas anotaciones.

Ahora un ejemplo muy muy simple de uno de los VOs anotados:

package com.viavansi.VO;
public class FooData1VO extends FooDataSuperVO{
@NombreBonito(alias="1. Terrenos y bienes naturales")
private Double balActInmInvTerrYBienNat;
@NombreBonito(alias="2. Infraestructuras y bienes destinados al uso general")
private Double balActInmInvInfYVBienUsoGral;
//etc..


//Con sus geterts y setters
}

Ya estamos terminando.

Con estas anotaciones solo necesitamos una JSF. Una para todos los VOs. Y un unico controller tambien.

En el Controller introducimos un par de getters de la siguiente pinta:

/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @author cvillar,dbejar
*@return
*/
public List<String> getListNombresBonitosProperties(){
if (listaPaginas.getRegistros().get(0) instanceof FooData1VO){
return new FooData1VO().getWiseNamedProperties();
}else if (listaPaginas.getRegistros().get(0) instanceof FooData2VO){
return new FooData2VO().getWiseNamedProperties();
}//else if [....]
//N veces
}else if (listaPaginas.getRegistros().get(0) instanceof FooDataNVO){
return new FooDataNVO().getWiseNamedProperties();
}else{
log.error("Primer registro de listaPaginas no es de un tipo VO implementado");
return new LinkedList<String>();
}
}
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseNamed
* @author cvillar,dbejar
*@return
*/
public List<String> getListWiseNamedLabels(){
//Trivial. La misma idea que el metodo anterior.
}

Y finalmente nuestra JSF universal y super simplificada:

<v:dataTable id="data" var="fila" styleClass="display_table" controller="#{FooDataController}">
<c:forEach var="propiedad" items="#{FooDataController.listWiseNamedProperties}" varStatus="rowCounter">
<v:column property="#{propiedad}" label="${FooDataController.listWiseNamedLabels [rowCounter.index]} "/>
</c:forEach>
</v:dataTable>

Hala pues,

Tips: Configurar una página JSF como página de inicio en Tomcat 5.5

05 ago 2007

Normalmente cuando queremos configurar una página como página de inicio de la aplicación, solo tenemos que indicar la página concreta en el apartado welcome-file-list de esta forma:

<welcome-file-list>
    <welcome-file>index.jsf</welcome-file>
</welcome-file-list>

Sorprendentemente este tipo de configuración estándar no funciona correctamente cuando la página destino es una .jsf (también aplicable a otras extensiones ficticias) , ya que Tomcat comprueba la existencia física del fichero.

Para conseguir esto, sin tener que recurrir a redirecciones, solo tenemos que crear junto al fichero index.xhtml un fichero index.jsf (que puede estar vacío).

La existencia física del fichero index.jsf es un truco que nos ayuda a salvar la limitación que impone Tomcat 5.5 cuando intenta localizar el fichero de bienvenida.

El fichero index.jsf, aunque puedes estar vacío, es recomendable que contenga algo como:

<%--
Please DO NOT delete this file. This file is used
to trick tomcat to detect index.jsf as the
welcome file and will load index.jsp instead.
Truco gracias a :

http://forum.java.sun.com/thread.jspa?threadID=696586&messageID=4044966

--%>