Omnifaces: una librería de utilidades para JSF2

0
15149

Omnifaces: una librería de utilidades para JSF2.

0. Índice de contenidos.


1. Introducción

Omnifaces es una librería de componentes para JSF2 que surje de las soluciones propuestas a problemas comunes sobre JSF2,
expuestos en el conocido Stack Overflow; es obra de BalusC y
Arjan Tijms; os sonarán si estáis acostumbrados a buscar información sobre JSF en el foro de Stack Overflow y en la web en general.

No es, en sí misma, una librería de componentes visuales, no suple a Primefaces, Richfaces o ICEfaces; de hecho los complementa, con lo que no son competidores.

Podéis echar un vistazo al showcase que está basado en primefaces, para comprobar todos los componentes que implementa.

Desde nuestro punto de vista, tiene algunos de aquellos componentes que teníamos implementados en nuestra propia librería
de componentes para JSF1.2, que estábamos trasladando a una nueva librería para JSF2 y que complementaban todos nuestros desarrollos.
Adicionalmente, recopila otros componentes bastante interesantes y otras utilidades muy recomendables; en este tutorial veremos algunas de ellas.

En la última versión soporta CDI e incorpora algunos componentes interesantes también si estamos
haciendo uso de la inyección de dependencias de JEE.

Y en relación a esto último tened en cuenta que gracias al soporte de JSF2 y al de CDI, muchos de esos componentes, interfaces o listeners que dan soporte a otros se autocomfiguran
por el mero hecho de incluir dentro de la librería los ficheros de configuración META-INF/faces-config.xml y META-INF/beans.xml.


2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.4 GHz Intel Core i7, 8GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Lion 10.7.4
  • JDK 1.7.0_11
  • JSF 2.1
  • WebSphere Application Server V8.5 Liberty Profile


3. Configuración.

La configuración de Omnifaces es muy simple puesto que basta con añadir la dependencia correspondiente:

<dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>1.6</version>
</dependency>

Si no tenemos el soporte de maven bastaría con incluir la librería en nuestro directorio de jars /WEB-INF/lib y si estamos trabajando en un proyecto que despliega bajo
una plataforma OSGI, deberíamos declarar la dependencia en el MANIFEST.MF

Bundle-ClassPath: .,
 WEB-INF/lib/primefaces-3.5.jar,
 WEB-INF/lib/omnifaces-1.6.jar

y en el build.properties

bin.includes = WEB-INF/lib/primefaces-3.5.jar,\
               WEB-INF/lib/omnifaces-1.6.jar

A partir de este momento ya podemos comenzar a usar el espacio de nombres en nuestros árboles de componentes visuales:

xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions"


4. Algunos componentes visuales.

Estos son algunos de los componentes visuales que incorpora la librería, hay más pero estos son en realidad lo más interesantes,
el resto podríamos decir que o están incorporados en Primefaces o no le vemos una utilidad inmediata.


4.1. <o:cache /> soporte para caché a nivel de componentes

Incorpora un componente de caché que, como su nombre indica, permite cachear la renderización de parte del árbol de componentes, de tal modo que se renderiza la primera vez y bien a nivel de aplicación o de sesión el resto de renderizaciones las están cacheadas.

Dispone de un sistema de descacheo a través de la invocación a un método de un managed bean y podemos crear nuestra propia implementación de cache para el componente aunque por defecto ya incorpora una basada en http://code.google.com/p/concurrentlinkedhashmap.

A continuación un ejemplo básico:

    <o:cache key="firstCache">
        <h:dataTable id="example1" value="#{cacheBean.items}" var="item">
            <h:column>
                <i>#{item}</i> <br/>
            </h:column>
        </h:dataTable>
    </o:cache>


4.2. <o:onloadScript />.

Extiende el componente <h:outputScript> y permite invocar a una función global de javascript en la carga de la página y con cualquier rerenderización de tipo ajax.


4.3. HTML5RenderKit

Añade soporte para la renderización de ciertos atributos que forman parte de la especificación de HTML5, de tal modo que
los componentes visuales incorporan esos atributos en su renderización en cliente.

Algo similar es lo que se ha incluido ya «out of the box» en la versón 2.2 de JSF.


5. Componentes no visuales.

En este punto, omnifaces ofrece todos aquellos conversores típicos que veníamos usando
para todos nuestros desarrollos y otros conceptos bastante más interesantes.


5.1. SelectItemsConverter

Evitar crear conversores individuales para cada tipo de objeto complejo a convertir dentro de un listado de opciones seleccionables. Lo más inmediato era recurrir a un conversor por tipo de objeto que en la operación convertAsObject acudía a base de datos mediante un dao
para traducir el identificador único a objeto; con lo que implica a nivel de rendimiento y accesos innecesarios a base de datos. Nosotros ya veníamos usando un conversor que se basada en el contenido propio de la lista que se almacena a nivel de árbol de componentes en memoria, evitando
esos accesos innecesarios y omnifaces incorpora un conversor con la misma filosofía. Por defecto, identifica unequívocamente un objeto invocando al método toString.

        <h:outputLabel for="selectitems" value="Items with SelectItem list: " />
        <h:selectOneMenu id="selectitems" value="#{selectItemsBean.selectedEntity}" converter="omnifaces.SelectItemsConverter">
            <f:selectItem itemLabel="Choose item" noSelectionOption="true" />
            <f:selectItems value="#{selectItemsBean.selectItems}" />
            <f:ajax render="selected_item" />
        </h:selectOneMenu>


5.2. CharacterEncodingFilter

Incorpora un filtro que asigna la codificación indicada a la request cuando desde el cliente no se especifica. Nosotros veníamos usando el filtro omónimo de Spring, que básicamente hace lo mismo.

<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


5.3. CDNResourceHandler

La renderización de recursos estáticos en el árbol DOM del cliente, con el soporte de JSF, siempre hace referencia a la descarga de los mismos
a través del contexto de la aplicación y vía javax.faces.resources; con ello, todos los recursos tipo javascript, css o
imágenes que vienen incorporados en las librerías de componentes de terceros que usamos en nuestro framework o que incorporamos vía:

	<h:outputStylesheet library="css" name="styles.css"> 
	<h:graphicImage library="images" name="image.jpg">
	#{resource['library/image.png']}

se descargan a través del servidor de aplicaciones.

Con CDNResourceHandler podemos añadir un prefijo o sustituir la renderización de la url para que no apunte al
contexto de JSF y nos permita añadir un alias a nivel de servidor web para que no llegen todas esas peticiones
al servidor de aplicaciones; lo que viene siendo un repositorio de estáticos.

Tendríamos la carga de trabajo de mantener actualizado el contenido del repositorio de estáticos con el contenido
de lo que ahora mantenemos empaquetado en nuestros proyectos y en los jars de las librerías de terceros, así todo el
javascript de la implementación de JSF y todas las imágenes, javascript y css de los temas de Primefaces.

Añadir el soporte es simple, en el faces-config.xml:

<application>
    <resource-handler>org.omnifaces.resourcehandler.CDNResourceHandler</resource-handler>
</application>

Y en el web.xml las expresiones que permitan realizar las sustituciones:

<context-param>
    <param-name>org.omnifaces.CDN_RESOURCE_HANDLER_URLS</param-name>
    <param-value>primefaces:*=#{request.contextPath}/estaticos/primefaces/*</param-value>
</context-param>

Han pensado en todo, porque permite el uso de Expression Language y además, por defecto, no está habilitado para el
entorno de desarrollo, si queremos habilitarlo siempre tenemos que añadir un parámetro de contexto también en el web.xml.

<context-param>
    <param-name>org.omnifaces.CDN_RESOURCE_HANDLER_ALWAYS_ENABLED</param-name>
    <param-value>true</param-value>
</context-param>

Con todo ello, las URLs de descarga de estáticos de Primefaces pasan de esto:

a esto otro:

muy bueno, teniendo en cuenta que el estándar no proporciona ese soporte y, en otro caso, tendríamos que programarlo
nosotros manualmente o incluir una regla de reescritura a nivel del servidor web.


6. EL functions.

Proporciona una extensión de Expresion Language que nos permite invocar a las siguientes funciones:

  • of:createArray(), of:createIntegerArray(), y of:contains(): en relación a Arrays.
  • of:iterableToList(), of:setToList(), of:mapToList(), of:joinArray(), of:joinCollection(), of:joinMap(), of:splitArray(), of:splitList(), y of:toJson(): para convertir tipos de datos.
  • of:formatDate(), of:formatDateWithTimezone(), of:addXxx() like of:addDays(), of:xxxBetween() like of:daysBetween(), of:getMonths(), of:getShortMonths(), of:getDaysOfWeek(), of:getShortDaysOfWeek(), of:getMonth(), of:getShortMonth(), of:getDayOfWeek() y of:getShortDayOfWeek(): para operar con fechas


7. Referencias.


8. Conclusiones.

Estos son los componentes y características más destacables, el resto os lo dejo a vosotros
y, sí os parece alguno más merecedor de mención, os animo a que lo incluyáis en los comentarios
de este tutorial o incluso a publicar uno vosotros mismos 😉

Un saludo.

Jose

jmsanchez@autentia.com

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad