Conferencia #6 Introducción a JavaServer Faces y Facelets. Componentes
administrados. Configuración de aplicaciones JSF.
Objetivos:
•
Introducir la tecnología JavaServer Faces.
•
Introducir la tecnología de vista Facelets.
•
Conocer los componentes administrados de JavaServer Faces.
•
Conocer los elementos de los ficheros de recurso de las aplicaciones JSF.
•
Conocer el alcance de los componentes administrados de JavaServer Faces.
Contenido:
•
Introducción.
•
Tecnología JavaServer Faces.
•
Tecnología Facelets.
•
Componentes administrados de la tecnología JSF.
•
Configuración de aplicaciones web con tecnología JSF.
•
Ficheros de recursos de JSF.
•
Alcance de los componentes administrados de JSF.
•
Conclusiones.
•
Motivación para la próxima clase.
Bibliografía:
1. Geary, David; Horstmann Cay. “Core JavaServer
TMFaces, Second Edition”.
Prentice Hall, 2007. ISBN: 978-0-13-173886-7. Capítulos 1,2.
2. Olsson, Tommy; O’Brien, Paul. “The Ultimate CSS Reference”. SitePoint Pty
Ltd, 2008. ISBN 978-0-9802858-5-7.Capítulo 18.
Introducción
En la clase anterior se analizaron las características de las aplicaciones empresariales
que permiten a los desarrolladores enfocarse en la lógica de negocio de los sistemas,
mientras que un conjunto de servicios de nivel de sistema tales como: persistencia,
transacciones, seguridad y mensajería, son gestionados por los servidores de
aplicaciones.
Se analizó la plataforma Java Enterprise Edition (Java EE) como la propuesta estándar
dentro del entorno Java para el desarrollo de aplicaciones empresariales. Se definió la
plataforma Java EE y los principales APIs que componen la misma, haciéndose
énfasis en la tecnología JavaServer Faces (JSF).
Las principales partes que contiene JSF se sintetizan en:
•
Conjunto prefabricado de componentes de interfaz de usuario.
•
Modelo de programación guiado por eventos.
•
Modelo de componentes que permite a los desarrolladores proporcionar sus
propios componentes.
Introducción a Facelets
Cuando JSF fue diseñado, la intención fue reutilizar JavaServer Pages (JSP) como la
tecnología principal para crear páginas, puesto que era un estándar dentro de la
comunidad de Java. La idea era simplificar la adopción de JSF usando un lenguaje
familiar de etiquetas, que un alto porcentaje de utilización.
Desafortunadamente las tecnologías JSP y JSF no se complementan naturalmente
una con otra, producto de la diferencia entre sus ciclos de vida. JSP es usado para
crear contenido web estático o dinámico, pero no para crear árbol de componentes.
Los elementos en JSP son procesados desde el inicio de la página hasta el final de la
misma, con el objetivo básico de producir una respuesta a una petición. El ciclo de
vida de JSF es más complicado, y la generación y visualización de componentes
ocurren en fases separadas.
Cuando JSF y JSP en conjunción producen una respuesta a una solicitud, difieren en
cómo lo realizan: el contenedor JSP crea salidas tan pronto como encuentra contenido
JSP, mientras que los componentes JSF dictan su propia visualización.
Los problemas entre JSP y JSF pueden frustrar a desarrolladores que usan por
primera vez JSF y desconocen los detalles de la implementación de JSP y JSF. En
este sentido surge Facelets como tecnología de vista enfocada en construir árboles de
componentes y disponiendo el contenido con el complejo ciclo de vida de JSF.
Facelets llena la abertura entre JSP y JSF, reemplazando JSP un con un API muy
simple e incorporando numerosas características útiles para el desarrollador.
Entre las múltiples ventajas que avalan el uso de Facelets se encuentran:
•
Independencia del contenedor web, pudiéndose utilizar JSF 1.2 sin tener
necesidad Java EE 5 o un contenedor que ya soporte JSP 2.1. Facelets trabaja
con cualquier implementación de JSF.
•
Brinda una solución para el problema de incompatibilidad entre JSP y JSF, al
mismo tiempo que proporciona un proceso de compilación más eficiente que
JSP, debido a que no se requiere generar ni compilar bytecodes de Java la
primera vez que se visita la página.
•
Proporciona una tecnología de plantillas que permite su reutilización de forma
extensiva en el código para simplificar el desarrollo y mantenimiento de las
aplicaciones. Permite la creación de componentes ligeros fáciles de
implementar comparados con los componentes puros de JSF.
•
Permite escribir páginas JSF como archivos XHTML los cuales mejoran
significativamente la legibilidad, productividad del desarrollador y rendimiento
en tiempo de ejecución comparado con páginas equivalentes escritas en JSP.
•
Soporte para depurar (debugging) aplicaciones desde el navegador. Si un error
ocurre cuando se visualiza una página, Facelets brinda la localización exacta
del error en el fichero fuente y facilita información del contexto alrededor del
error.
Las ventajas antes mencionadas condicionan la elección de Facelets, como tecnología
de exposición para JSF, implementando las vistas en archivos XHTML en lugar de
JSP.
Diferencias entre XHTML y HTML
La diferencia más importante entre los dos lenguajes de marcado HyperText Markup
Language (HTML) y Extensible HyperText Markup Language (XHTML), consiste en
que HTML es una aplicación de Standard Generalized Markup Language (SGML),
permitiendo que los desarrolladores omitan ciertas etiquetas y usen la minimización de
atributos. Por su parte XHTML es una aplicación de XML, la cual no permite la omisión
de ninguna etiqueta o la utilización de minimización de atributos. Sin embargo XHTML,
proporciona una notación corta para elementos vacíos, como por ejemplo, <br/> en
lugar de <br></br>.
Los documentos XML deben cumplir la condición de estar bien-formados, significando
que debe existir el cierre de una etiqueta por cada etiqueta abierta y que las etiquetas
anidadas, es decir, las que se encuentran dentro de otra etiqueta, deben ser cerradas
en el orden correcto. Cuando un analizador (parser) XML detecta un error relacionado
a un documento mal-formado aborta la interpretación del mismo, mientras que un
analizador HTML ante la misma situación intenta recuperarse y continuar el
procesamiento.
Espacios de nombres de XML
La tecnología XML permite a los autores de documentos crear sus propias etiquetas.
Esta extensibilidad puede resultar en colisiones de nombres entre los elementos de un
documento XML. La utilización de espacios de nombres (namespace) para agrupar
etiquetas o elementos, permite ligar un prefijo a una cadena de caracteres llamada
Identificador Uniforme del Recursos (URI, por su nombre en inglés Uniform Resource
Identifier), que identificará al espacio de forma inequívoca. Los autores de documentos
pueden crear sus propios prefijos namespace y URIs. Las URIs es una forma de
identificar un recurso típicamente sobre Internet. Las tipos más populares de URIs son
el Nombre Uniforme de Recursos (URN, de su nombre en inglés Uniform Resource
Name) y Localizador Uniforme de Recursos (URL, de su nombre en inglés Uniform
Resource Locator).
Definición de JavaBeans
De acuerdo con la especificación de JavaBeans o simplemente beans (disponible en
http://java.sun.com/products/javabeans/
), un JavaBean es “un componente software
reutilizable que puede ser manipulado en una herramienta gráfica”. Esta es una
definición bastante amplia y como se verá, los beans son usados en una variedad de
propósitos.
Un bean es una clase que expone sus propiedades y métodos siguiendo un patrón. La
forma más simple de definir una propiedad es usar un convenio estándar para los
métodos de lectura y escritura, particularmente la convención familiar del set/get. La
primera letra del nombre de la propiedad es cambiada a mayúscula en los nombres de
los métodos.
Los objetos son creados y manipulados dentro un programa Java cuando el programa
llama los constructores e invoca a los métodos. Los beans son creados y manipulados
sin programación.
Presentación del caso de estudio de JSF: Aplicación login
Para empezar el estudio de los componentes administrados de JSF, se presenta una
aplicación ejemplo cuya estructura consiste en:
•
Páginas login.xhtml y welcome.xhtml que definen las pantallas de login y
welcome respectivamente.
•
El bean UserBean que administra los datos del usuario, en este caso name y
password. Esta clase está contenida en el paquete com.core.jsf.
•
El fichero de configuración faces-config.xml que lista los beans y las reglas de
navegación.
•
Ficheros como el web.xml que son necesitados en la configuración del
contenedor de Servlets, y el index.html que redirecciona al usuario a la correcta
URL para la página de login.
Aplicaciones JSF más avanzadas tienen la misma estructura, pero pueden contener
clases adicionales tales como manejadores de eventos, validadores y componentes
personalizados.
Fig. 1 Estructura de despliegue del ejemplo
Fig. 2 Definición de la clase UserBean
Fig. 3 Fichero fuente index.xhtml
Por el momento destacar los siguientes elementos:
•
Existe un número de etiquetas estándares de HTML: body, table, entre otras.
•
Algunas etiquetas tienen prefijos como: h:inputText, las cuales forman parte de
las etiquetas de JSF. La declaración de xmlns es el namespace por defecto de
los archivos xhtml, mientras que xmlns:f y xmlns:h son los namespace donde
se encuentran las etiquetas del núcleo y html de JSF respectivamente.
•
Las etiquetas h:inputText, h:inputSecret y h:commandButton corresponden al
campo de texto, campo de contraseña y botón de tipo submit.
•
Los campos de entrada están enlazados a propiedades de los beans. Por
ejemplo el atributo value=”#{user.name}” le dice a la implementación de JSF
que enlace el campo de texto con la propiedad name del objeto user.
Análisis del caso de estudio de JSF
Las aplicaciones web presentan 2 partes: la capa de presentación y la capa de lógica
de negocio. La capa de presentación es responsable de la apariencia de la aplicación.
En el contexto de un aplicación web la apariencia es determinada por la etiquetas
HTML que especifican el diseño, fuentes, imágenes, entre otros. La lógica de negocio
es implementada en el código Java que determina el comportamiento de la aplicación.
Algunas tecnologías web entremezclan código de lógica de negocio y HTML. Esta
metodología es atractiva y fácil para el desarrollo de aplicaciones de baja complejidad.
Sin embargo, para aplicaciones de gran envergadura mezclar la lógica de negocio y
HTML plantea grandes problemas. Diseñar aplicaciones web profesionales, conlleva
separar la presentación de la lógica de negocio, permitiendo una clara división en roles
debido que diseñadores y desarrolladores se enfocan en sus habilidades.
En el contexto de JSF, el código de la aplicación es contenido en los beans y el diseño
es contenido en las páginas web, en este caso ficheros XHTML.
Los JavaBeans exponen propiedades y eventos en entornos como JSF. La clase
UserBean tiene dos propiedades de tipo String: name y password. En las aplicaciones
JSF los beans se utilizan para todos los datos que necesitan ser accesibles desde una
página. Estos componentes son los conductos entre la interfaz de usuario y la parte
trasera de la aplicación.
Páginas JSF
La extensión de los ficheros de las páginas es .xhtml, mientras que en la configuración
preferida, la extensión de las URLs de las páginas es .faces. Cuando el navegador
solicita la URL http://localhost:8080/login/index.faces, la extensión de la URL .faces es
mapeada a la extensión .xhtml y el contenedor de servlet carga el fichero index.xhtml.
Este proceso parece ser raro, pero es una consecuencia de la implementación de JSF
en el tope de la tecnología servlet.
Las páginas comienzan con la declaración de las etiquetas de librería:
Fig. 4 Declaración del fichero index.xhtml
La implementación de JSF define dos conjuntos de etiquetas, las cuales son
accesibles a través de su namespace. Las etiquetas HTML generan elementos
específicos de HTML. Si el desarrollador quisiera visualizar páginas para una
tecnología cliente alternativa, se debe utilizar una librería de etiquetas diferentes. Las
etiquetas que pertenecen al namespace core son independientes de la tecnología de
visualización.
La página JSF index.xhtml tiene similitudes con un formulario HTML común,
destacando las siguientes diferencias:
•
En lugar de utilizar una etiqueta form de HTML, todos los componentes JSF
van encerrados en una etiqueta h:form.
•
En lugar de utilizar las etiquetas de entrada de HTML, se usa h:inputText,
h:inputSecret y h:commandButton.
Los valores de los campos de entrada están ligados a propiedades del bean
UserBean, por ejemplo:
Cuando la página es visualizada, JSF invoca el método getName para obtener el valor
actual de la propiedad name. Cuando la página es enviada (submitted), JSF invoca el
método setName para establecer el valor que el usuario introdujo a la propiedad name.
La etiqueta h:commandButton tiene una acción cuyo valor es usado cuando se
especifican la reglas de navegación:
<h:commandButton value="Login" action="login"/>
La segunda página de la aplicación ejemplo, welcome.xhtml es más simple que la
primera (Fig. 5). En ella se emplea la etiqueta h:outputText para visualizar el nombre
del usuario.
Fig. 5 Página welcome.xhtml
Fichero de configuración faces-config.xml
Facelets aprovecha la propia naturaleza de JSF para reemplazar el ViewHandler
(manejador de vista) de esta con su propia implementación representada por la clase
com.sun.facelets.FaceletViewHandler. Para configurar el ViewHandler de Facelets en
la aplicación web ejemplo en lugar del ViewHandler por defecto de JSF, se especifica
este elemento en la etiqueta <view-handler> en el fichero de configuración
faces-config.xml (Fig. 6):
Fig. 6 Configuración de Facelets
Para completar la aplicación de ejemplo se especifican las reglas de navegación. Una
regla de navegación le dice a la implementación JSF cual página devolver al
navegador después que un formulario ha sido enviado. La regla de navegación de este
ejemplo es bastante simple. Cuando el usuario pulsa el botón Login, se produce una
navegación desde la página index.xhtml a la página welcome.xhtml, mediante la regla
especificada en el fichero faces-config.xml (Fig. 7):
Fig. 7 Reglas de navegación de la aplicación ejemplo
El elemento from-outcome enlaza con el atributo action del botón Login en la página
index.xhtml:
<h:commandButton value="Login" action="login"/>
Además de las reglas de navegación el fichero faces-config.xml contiene la definición
de los beans de JSF o componentes administrados de JSF. En la Fig. 8 se muestra la
definición del bean UserBean de la aplicación ejemplo:
Fig. 8 Definición del bean UserBean.
Una vez definido el bean en el fichero de configuración, se puede usar su nombre o
alias en los componentes de interfaz de usuario. Por ejemplo la página index.xhtml
contiene la etiqueta:
<h:inputText value=”#{user.name}” />
El atributo value se refiere a la propiedad name del bean user.
La etiqueta managed-bean-class especifica la clase del bean, en el caso del ejemplo
com.corejsf.UserBean. Finalmente el alcance (scope) del bean es establecido a
session. Esto significa que el objeto del bean está disponible para el mismo usuario a
través de múltiples páginas. Diferentes usuarios que utilizan la aplicación web tienen
diferentes instancias del objeto del bean.
Como se puede apreciar, el desarrollador no necesita escribir ningún código para
construir y manipular el bean. La implementación de JSF construye los beans de
acuerdo con los elementos managed-bean en el fichero de configuración
faces-config.xml.
En una aplicación JSF, los beans son comúnmente utilizados para los siguientes
propósitos:
•
Componentes de interfaz de usuario (beans interfaces de usuario tradicionales)
•
Atar el comportamiento de un formulario web (denominados “backing beans”)
•
Objetos de negocio cuyas propiedades son visualizadas en páginas web
•
Servicios tales como fuentes de datos externas que necesitan ser configurados
cuando la aplicación es ensamblada
Fig. 9 Fichero faces-config.xml de la aplicación ejemplo
Configuración del Servlet de JSF
Cuando se despliega una aplicación JSF dentro un servidor de aplicación, se necesita
suministrar un fichero de configuración nombrado web.xml (Ver Fig. 10).
Afortunadamente se puede usar el mismo fichero web.xml para la mayoría de las
aplicaciones JSF.
El único aspecto notable de este fichero de configuración es el mapeo de servlets
(servlet mapping). Todas las páginas JSF son procesadas por un servlet especial,
javax.faces.webapp.FacesServlet, que es parte del código de implementación de JSF.
Para asegurarse que el servlet correcto es activado cuando una página JSF es
solicitada, las URLs de JSF tienen un formato especial, que en caso del ejemplo tienen
la extensión .faces.
El navegador no puede apuntar a la dirección http://localhost:8080/login/index.xhtml, la
URL tiene que ser http://localhost:8080/login/index.faces. El contenedor web usa la
regla de mapeo del servlet para activar el servlet de JSF, el quita el sufijo faces y
carga la página index.xhtml para procesarla.
Procesamiento interno de la aplicación ejemplo
Cuando
el
usuario
apunta
la
dirección
del
navegador
a
http://localhost:8080/login/index.faces, el servlet de JSF inicializa el código de JSF y
lee la página index.xhtml. Esta página contiene etiquetas tales como: h:form,
h:inputText y h:inputSecret. Cada etiqueta tiene una clase controladora de etiqueta
asociada, de forma que cuando la página es leída, los controladores de etiquetas son
ejecutados. Los controladores de etiquetas de JSF colaboran entre ellos para construir
un árbol de componentes (Ver Fig. 11).
Fig. 11 Arbol de componentes de la aplicación ejemplo
El árbol de componentes es una estructura de datos que contiene objetos de Java
para todos los elementos de la interfaz de usuario contenidos en la página JSF. Por
ejemplo, los dos objetos UIInput corresponden a las etiquetas h:inputText y
h:inputSecret, mientras que UICommand corresponde al botón Login de la página
index.xhtml.
Visualización de las páginas JSF
Posteriormente la página HTML es visualizada, donde todos los textos que no son
etiquetas JSF son enviados en la respuesta sin procesamiento de ningún tipo. En
cambio, las etiquetas h:form, h:inputText y h:inputSecret son convertidos en elementos
HTML.
Como se analizó anteriormente, cada una de estas etiquetas da lugar a un
componente asociado. Cada componente tiene un visualizador que produce una salida
HTML, reflejando el estado del componente. Por ejemplo, el visualizador para el
componente que corresponde a la etiqueta h:inputText produce la siguiente salida:
<input type="text" name="unique ID" value="current value"/>
Este proceso es nombrado codificación. El visualizador del objeto UIInput pregunta al
framework de JSF para buscar el Id único y el valor actual de la expresión user.name.
Por defecto los Id de tipo cadena de texto, son asignados por el framework. Los Ids
pueden parecer más bien aleatorios, tal como: _id_id12:_id_id21. La página codificada
es enviado de regreso al navegador, y este la visualiza en la forma usual.
Decodificación de peticiones
Posterior a la visualización de la página, el usuario llena los campos del formulario y
pulsa el botón Login. El navegador envía los datos del formulario de regreso al
servidor web, formateada como una petición POST. La petición POST contiene la URL
en la forma (login/faces/index.faces), además de los datos del formulario.
Los datos del formulario es un cadena de texto de pares ID/valor tales como:
id1=me&id2=secret&id3=Login
Como parte del procesamiento normal del servlet, los datos del formulario son
colocados en una tabla hash (Hashtable) que todos los componentes pueden acceder.
Después el framework de JSF le brinda la oportunidad a cada componente de
inspeccionar la tabla hash, proceso denominado decodificación de la petición. Cada
componente decide por si mismo cómo interpretar los datos del formulario.
El formulario de login tiene tres objetos de componentes: dos UIInput que
corresponden a los campos de texto del formulario y un UICommand asociado al botón
de submit.
•
Los componentes UIInput modifican las propiedades del bean (en este caso
UserBean) referenciadas en los atributos value: ellos invocan los métodos
setter los valores que el usuario introdujo.
•
El componente UICommand chequea si el botón ha sido pulsado. En caso
positivo, él dispara un evento de acción para iniciar la acción login referenciada
en el atributo action. Este evento le dice al manejador de navegación
(navigation handler) buscar la página que sucede, en este caso welcome.faces.
Fichero de recursos
Cuando se implementa una aplicación web es una buena práctica recolectar todas las
cadenas de mensajes en una ubicación central. Este proceso hace fácil de guardar
mensajes de forma consistente y crucialmente, regionalizar la aplicación a otros
idiomas. Las cadenas de mensajes son recolectados en un fichero de propiedades
(extensión .properties). Los mensajes tienen el formato de llave/valor:
guessNext=Guess the next number in the sequence!
answer=Your answer:
Los ficheros de menajes pueden ser declarados de dos formas. La forma más simple
es incluir los siguientes elementos en el fichero de configuración faces-config.xml (Ver
Fig. 12):
Alternativamente se puede añadir el elemento f:loadBundle a cada página que
necesita acceso al fichero de recurso:
<f:loadBundle basename="com.corejsf.messages" var="msgs"/>
En ambos casos el fichero de mensajes es accesible a través de una variable de tipo
Map con el nombre msgs. Se pueden utilizar expresiones como estas para acceder a
las cadenas de mensajes:
<h:outputText value="#{msgs.guessNext}"/>
Backing Beans
En algunas ocasiones es conveniente diseñar un bean que contenga algunos o todos
los objetos componentes de un formulario web. Tales bean se denominan “backing
beans” del formulario web. La Figura 13 presenta un backing bean de ejemplo:
Fig. 13 Ejemplo de Backing Bean