Pautas asociadas a la construcción de Seam

LIBP-0042 (Libro de pautas)

Se deben tener en cuenta las siguientes pautas para mejorar la construcción de la capa de negocio utilizando Seam.

Pautas

TítuloCarácter
Integrar un proveedor de caché en SeamObligatoria
Hacer un buen uso del proveedor de caché en SeamObligatoria
Guardar en caché los fragmentos de las páginas que no se modificanObligatoria
Cómo manejar el EntityManager en SeamObligatoria
Uso de la biyección de dependenciasObligatoria
Manejo de la identidad de los usuariosObligatoria
Manejo de las restricciones de accesoObligatoria

Integrar un proveedor de caché en Seam

Madeja recomienda introducir un proveedor de cache en Seam para mejorar el rendimiento de la aplicación.

Seam hace que sea sencillo lograr un aumento del rendimiento mediante la integración con un proveedor de caché . Hay tres proveedores de caché con el soporte en Seam: JBoss Cache, Boss POJO Cache y EHCache. Es necesario configurar en fichero de configuración (Treecache.xml en el caso del Jboss Cache y ehcache.xml, en el caso de usar EHcache) y declararlo en el fichero de componentes components.xml:

<components xmlns="http://jboss.com/products/seam/components"
            xmlns:cache="http://jboss.com/products/seam/cache">
   <cache:jboss-cache-provider configuration="META-INF/cache/treecache.xml" />
</components>

Hacer un buen uso del proveedor de caché en Seam

El proveedor de caché (CacheProvider) dispone de una API que dispone de los siguientes métodos que pueden referenciarse por anotaciones como cualquier componente Seam.

MétodoDescripción
put(String region, String key, Object object)Aloja un objeto en caché dándole una clave y una región
get(String region, String key)Deuvelve un objeto de la caché con una región y una clave asociada
remove(String region, String key)Elimina el objeto de caché

Y aquí un ejemplo de uso:

@Name("chatroomUsers")
@Scope(ScopeType.STATELESS)
public class ChatroomUsers

{
    @In CacheProvider cacheProvider;
    @Unwrap
    public Set<String> getUsers() throws CacheException   {
        Set<String> userList = (Set<String>) cacheProvider.get("chatroom", "userList");
        if (userList==null) {
            userList = new HashSet<String>();
            cacheProvider.put("chatroom", "userList", userList);
        }
        return userList;
    }
}

Guardar en caché los fragmentos de las páginas que no se modifican

MADEJA recomienda el almacenamiento de fragmentos de páginas de JSF para aumentar el rendimiento en la representación de las mismas.

En muchas páginas, hay información que rara vez se modifica y que se muestra de forma continua en las vistas. Esta información es muy recomendable guardarla en caché, ya que al no presentar cambios y ser de continuo acceso, se necesita una alta disponibilidad. Seam proporciona la capacidad de almacenar fragmentos de la página JSF en caché mediante el uso de la etiqueta <s:cache>. Esta habilidad facilita un aumento del rendimiento en el tiempo necesario para la representación de las vistas.

<s:cache key="recentEntries-#{blog.id}" region="welcomePageFragments">
   <h:dataTable value="#{blog.recentEntries}" var="blogEntry">
      <h:column>
         <h3>#{blogEntry.title}</h3>
         <div>
            <s:formattedText value="#{blogEntry.body}"/>
         </div>
      </h:column>
   </h:dataTable>
</s:cache>

Cómo manejar el EntityManager en Seam

Con la llegada de EJB 3 y JPA nace la figura del EntityManager para simplificar la persistencia de objetos. Y gracias a las anotaciones, el EntityManager puede ser inyectado por el contenedor de EJBs. Vamos a ver diferentes formas de obtener un EntityManager en Seam a través de anotaciones.

  • El EntityManager es inyectado directamente por el EJB container, y estará disponible aún después de que la transacción haya sido completada. Las entidades pueden seguir asociadas al contexto de persistencia durante varias interacciones.
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager entityManager;
  • El EntityManager es inyectado por Seam y asociado al contexto de conversación, con las mismas características que un EntityManager de tipo extendido.
@In EntityManager entityManager;

Uso de la biyección de dependencias

Madeja recomienda el uso de la biyección de dependencias proporcionado por Seam

Seam recomienda el uso de los objetos con estado. Uno de los principales problemas de la integración de JSF con los frameworks de negocio es el uso de los mismos. Seam propone el uso de la biyección de dependencias para minimizar estos problemas.

Un componente es un objeto con estado (normalmente stateful session beans). Una instancia de un componente vive en un contexto y se le asigna un nombre en dicho contexto. Para asociar la instancia de un componente al nombre de dicho componente en un contexto Seam proporciona el mecanismo de Biyección, que agrupa a dos mecanismos: injection y outjection

El mecanismo de inyección (injection) permite a un componente A obtener de un contexto una referencia a una instancia de un componente B, haciendo que el contenedor de aplicaciones ”inyecte” el componente B en una variable del componente A. El mecanismo de outjection permite que un componente B esté disponible en un contexto para poder ser inyectado en un componente A. Es decir, mediante outjection se toma una instancia de un componente y se deposita en un contexto, y mediante injection se toma una instancia de un componente de un contexto y se asocia a una variable de otro componente.

@In es para inyectar componentes de la aplicación en el componente actual. La anotación @In puede recibir valores:

  • create=true/false que indica si se crea el componente en caso de que no exista (o lo que es lo mismo en caso de que Seam no lo haya creado en una petición anterior),.
  • required=true/false indicando si el componente debe estar creado con anterioridad, en caso de que no exista la aplicación ha fallado y debería lanzarse una excepción.
  • y los relacionados con el scope y el value que son el ámbito y el nombre del componente.

@Out es para "outyectar" componentes, o dicho de otra forma inyectar hacia fuera y de ahí el término biyección que utiliza Seam. La anotación @Out puede recibir valores:

  • required=true/false.
  • scope=relacionado con el ámbito.
  • value=relaciona con el nombre del contexto.

Manejo de la identidad de los usuarios

Es muy recomendable realizar un un control sobre la identidad y los accesos permitidos de cada usuario. Seam proporciona una API que permite el manejo de la identidad del usuario y los roles. El IdentityManager proporciona soporte para las siguientes cuestiones:

  • Autenticación contra la configuración de almacenamiento de identidades.
  • Operaciones CRUD (crear, leer, actualizar y eliminar) para los usuarios y roles.
  • La concesión y revocación de funciones, cambiar contraseñas, activar y desactivar el usuario cuentas, el listado de usuarios y roles, etc.

El componente IdentityStore interactúa con el proveedor. Solo necesita configurar apropiadamente la instancia de IdentityStore para ser inyectada en el manejador IdentityManager en tiempo de ejecución. Puede crear un proveedor que implemente la interfaz IdentityStore y configurado para la inyección. Seam hace uso de las anotaciones para manejar la identidad de los usuarios, a continuación en una tabla se resumen las más importantes.

AnotaciónUsoEntidadDescripción
@UserPrincipalCampo, métodouser entityEsta anotación delimita el campo o método que contiene el nombre de usuario
@UserPasswordCampo, Métodouser entityEsta anotación delimita el campo o método que contiene la contraseña del usuario
@UserrolesCampo, Métodouser entityEsta anotación delimita el campo o método que contiene los roles del usuario
@RolenameCampo, Métodorole entityEsta anotación delimita el campo o método que contiene el nombre del rol del usuario

Y un ejemplo de uso:

@Entity
@Name("user")
@Scope(SESSION)
@Table(name="Customer")
  public class User implements Serializable
  {
    private String username;
    private String password;
    private List<Role> roles;
    // ... ...
    @UserPrincipal
    @Id
    @Length(min=5, max=15)
    @Pattern(regex="^\\w*$", message="not a valid username")
  public String getUsername()
  {
    return username;
  }
  public void setUsername(String username)
  {
    this.username = username;
  }
  @UserRoles
  @ManyToMany(fetch=FetchType.EAGER)
  @JoinTable(joinColumns={ @JoinColumn(name="USERNAME") },
   inverseJoinColumns={ @JoinColumn(name="ID")
   }
  )
  public List<Role> getRoles()
  {
    return roles;
  }
  public void setRoles(List<Role> roles)
  {
   this.roles = roles;
  }

Manejo de las restricciones de acceso

En ocasiones es necesario restringir el acceso en función de los tipos de usuarios de una aplicación. En Seam existe la posibilidad de restringir para controlar el acceso de los usuarios a determinados métodos. Para ello utiliza la anotación @Restrict. Las restricciones pueden ser expresadas usando cualquier expresión EL (usalmente incluyen s:hasrole()..o s:haspermission())

@Stateful
@Scope(EVENT)
@Name("changePassword")
public class ChangePasswordAction implements ChangePassword
{
  @Restrict("#{identity.loggedIn}")
  public void changePassword()
  {
   .....