Pautas de Integración JSF - Seam

LIBP-0053 (Libro de pautas)

JBoss Seam ofrece un alto grado de integración con JSF, de hecho por defecto viene integrado con la implementación de RichFaces y el uso de Facelets. A continuación se resumen un conjunto de recomendaciones para aumentar el rendimiento y la eficiencia de JSF mediante propiedades de Seam

Pautas

TítuloCarácter
Configuración básica para integrar JSF con SEAMObligatoria
Indicar los campos que necesitan validación dentro de pagina JSFObligatoria
Como propagar con las conversaciones desde los componentes JSFObligatoria
Acción por defecto de un formulario JSFObligatoria
Utilizar la navegación de páginas de SeamRecomendada
Uso de anotaciones para crear componentes Seam como validadores y conversores JSFRecomendada
Mejora en el lenguaje de expresión EL de JSFObligatoria

Configuración básica para integrar JSF con SEAM

Es necesario incluir en la configuración el listener general de Seam y es totalmente obligatorio, ya que es el encargado de gestionar todas las peticiones Seam. Es el encargado de destruir a la sesión y contextos de aplicación.

<listener>
    <listener-class>
        org.jboss.seam.servlet.SeamListener
    </listener-class>
</listener>

Así mismo es necesario incluir el servlet para las componentes JSF. El filtro de este también apunta a *.seam esto implica que todas las peticiones serán reenviadas a un bean con la extensión *.seam y como ya vimos en nuestro faces-config.xml estos beans serán los que nosotros creemos para Seam.

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.seam</url-pattern>
</servlet-mapping>

Algunas implementaciones tienen una implementación del almacenamiento del estado rota que interfiere en la propagación de la conversación Seam. Si tiene problemas con la propagación de la conversación Seam en el envió de formularios, intente utilizar el almacenamiento de estado en el lado del cliente.Para ello necesita declarar en el Web.xml:

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

Indicar los campos que necesitan validación dentro de pagina JSF

Se recomienda el uso de la etiqueta s:validateAll para incluir validaciones definidas en el modelo de datos

Si te envuelves en un formulario completo con el componente s:validateAll ,Seam le permite cumplir con las validaciones definidas en su modelo de datos durante el proceso de fase de Validaciones JSF. Este enfoque de la validación es mucho más atractiva que la dispersión de etiquetas de JSF validadoras por todas sus vistas o el mantenimiento de un archivo de configuración completo de definiciones de validación de un marco de validación de terceros.

En su lugar, puede utilizar las anotaciones de Hibernate Validator para asignar los criterios de validación de las propiedades de la clase de entidad. Hibernate comprueba la validación cuando persiste el objeto, dándole una doble de la protección. Este enfoque de doble puño significa que los errores por descuido introducidos en la vista no tienen la oportunidad de poner en peligro la calidad de sus datos. Un ejemplo de uso sería el siguiente:

<f:view>
  <h:messages/></div>

  <h:form>
   <s:validateAll>
    Please enter your address:<br/>
   <h:inputText value="#{house.address}" size="15"/><br/>
   <h:commandButton value="Add House" action="#{salesManager.addHouse}"/>
   </s:validateAll>
  </h:form>
</f:view>

Como propagar con las conversaciones desde los componentes JSF

Seam propaga de forma transparente el contexto de la conversación (incluyendo la conversación temporal) a través de las redirecciones y vueltas atrás de JSF. Si no se hace nada especial, un petición no faces, no propaga el contexto de la conversación y serán procesados en una nueva conversación temporal. Si realmente quiere propagarse el contexto hay que especificarlo explícitamente el código

La etiqueta pueden usarse para iniciar y finalizar la conversación, o para comenzar una conversación anidada.

<h:commandLink action="main" value="Exit">
<s:conversationPropagation type="end"/>
</h:commandLink>

Este modelo de conversación hace que sea fácil crear aplicaciones que se comportan correctamente con respecto al manejo de múltiples ventanas. Para muchas aplicaciones, esto es todo lo que se necesita.

Acción por defecto de un formulario JSF

A la hora de enviar un formulario, es muy habitual que si nos encontramos en un Input y se efectúa una acción de envío (ejemplo, pulsar enter), el formulario automáticamente se envía. ¿Como podríamos modificar este comportamiento trabajando con JSF? De momento, la especificación no contempla este caso.

Mediante el uso de Seam, si podemos añadir una funcionalidad que nos modifique el funcionamiento por defecto. Esto lo puedes hacer con la etiqueta <s:defaultAction>, que permite cambiar la acción que se ejecuta por defecto al presionar el enter

<a4j:commandButton action="#{handin.handin}" value="#{messages['generic.button.ok']}" reRender="pollForProgrammingResult, pinCodePanel, feedbackPanel">
<s:defaultAction/>
</a4j:commandButton>

Utilizar la navegación de páginas de Seam

Seam proporciona un mecanismo mucho mas inteligente para organizar las transiciones entre páginas del que ofrece JSF en el faces-config.xml. Cuando se definen reglas de navegación puede beneficiarse de las siguientes ventajas añadida a la navegación tradicional:

  • Usar un valor arbitrario inyectado para determinar la salida usando el método de retorno del manejador de la acción
  • Crear casos de navegación condicional usando expresiones inyectadas
  • Indicar como se puede propagar la conversación a través de la transición
  • Control del flujo de la página y los procesos de negocio a través de la transición

Las aplicaciones Seam utilizan un mecanismo similar para la realización del flujo de la página. Sin embargo, se definen dentro de un archivo pages.xml, que se almacena en la carpeta / WEB-INF de una aplicación web. archivo Es posible combinar los dos estilos (JSF y Seam) mediante la definición de flujos de página tanto en las faces-config.xml, así como el archivo pages.xml. Sin embargo, en aplicaciones más grandes, esto se tornará inmanejable y difícil de apoyar. Se recomienda que la lógica flujo de la página se almacene en el archivo pages.xml para asegurarse de que la lógica de flujo de la página se define en un lugar central.

<page view-id="/FacilityEdit.xhtml">
  <navigation from-action="#{facilityHome.persist}">
    <rule if-outcome="persisted"
      if="#{facilityHome.addCourse}">
      <redirect view-id="/CourseEdit.xhtml"/>
        <param name="courseFrom" value="Facility"/> #2
         <message severity="INFO">
           Please enter course information for
           #{facilityHome.instance.name}. #3
         </message>
      </redirect>
    </rule>
    <rule if-outcome="persisted"
      if="#{!facilityHome.addCourse}"> #4
      <redirect view-id="/Facility.xhtml"/>
    </rule>
  </navigation>
</page>

Uso de anotaciones para crear componentes Seam como validadores y conversores JSF

Seam provee anotaciones que permiten usar Componentes Seam como conversores y validadores de JSF Si aplicamos la anotación @Converter a un componente Seam se puede utilizar como un conversor. Es recomendable crear los conversores individualizados de esta manera.

@Name("itemConverter") 
    @BypassInterceptors
    @Converter
    public class ItemConverter implements Converter {      
       @Transactional
       public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
          EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
          entityManager.joinTransaction();
          // Do the conversion
       }
       public String getAsString(FacesContext context, UIComponent cmp, Object value) {
          // Do the conversion
       }    
    }

// Utilización en JSF

    <h:inputText value="#{shop.item}" converter="itemConverter" />

El conversor puede acceder a un EntityManager dentro de una transacción JTA que convierte el valor de vuelta.

Con la anotación @Validador se convierte un componente Seam en un validador JSF, es muy recomendable utilizar esta capacidad de Seam para crear validadores específicos en la aplicación.

@Name("itemValidator") 
    @BypassInterceptors
    @org.jboss.seam.annotations.faces.Validator
    public class ItemValidator implements javax.faces.validator.Validator {        
       public void validate(FacesContext context, UIComponent cmp, Object value)
             throws ValidatorException {
          ItemController ItemController = (ItemController) Component.getInstance("itemController");
          boolean valid = itemController.validate(value);
          if (!valid) {
             throw ValidatorException("Invalid value " + value);
          }
       }
    }

// Utilización en JSF

    <h:inputText value="#{shop.item}" validator="itemValidator" />

Registra el componente Seam como un validador JSF. El validador es inyectado en otro componente Seam , el componente inyectado es usado para validar el valor

Mejora en el lenguaje de expresión EL de JSF

Se recomienda utilizar el lenguaje de expresión EL extendido por Seam ya que permite introducir llamadas con argumentos a los componentes en las páginas JSF

En el estándar de JSF, la propiedad (value expression) y el método (method expression) del componente respaldado son lo mismo. Como resultado, el método de expresión no puede hacer ninguna llamada con argumentos, por ejemplo, la propiedad "name" sobre le componente persona se expresa de la siguiente manera:

<h:inputText value="#{person.name}" size="15"/>

El manejador de eventos del método esta escrito de la misma manera, y tampoco puede hacer llamadas con argumentos . Todos los objetos del método deben de ser inyectados en el método previamente a que el método es llamado como por ejemplo:

<h:commandButton type="submit"
value="Say Hello"
action="#{manager.sayHello}"/>

Seam extiende el lenguaje EL, ahora puedes llamar a cualquier componente método con el () para mejorar la lectura. Por lo tanto el método puede realizar llamadas con argumentos también. Así, ya no es necesario introducir realizar la inyección previa. Esto reduce las necesidades de para la inyección de dependencias y convierte la aplicación en mas fácil para la lectura

<h:commandButton type="submit"
value="Say Hello"
action="#{manager.sayHello(person)}"/>

Así la nueva clase del ManagerAction quedaría con el nuevo método sayHello() de la siguiente manera:

@Stateless
@Name("manager")
public class ManagerAction implements Manager {
  private Person person;
  @Out
  private List <Person> fans;
  @PersistenceContext
  private EntityManager em;
  public void sayHello (Person p) {
  em.persist (p);
  fans = em.createQuery("select p from Person p").getResultList();
 }
}

Seam no solo hace expansión del lenguaje EL, también permite que el lenguaje EL este disponible mas allá de las paginas web. En una aplicación Seam, puedes usar expresiones JSF para substituir código estático en ficheros de configuración, tests, mensajes JSF, etc. El uso expandido del lenguaje EL de JSF simplifica el desarrollo.