Programación en castellano
Inicio > Tutoriales > J2EE > Catálogo de Patrones de Diseño J2EE. Y II: Capas de Negocio y de Integración
-Tutoriales

Catálogo de Patrones de Diseño J2EE. Y II: Capas de Negocio y de Integración


Value List Handler

. Contexto

El cliente le pide al servicio una lista de ítems para su presentación. El número de ítems de la lista no se conoce y puede ser muy grande en muchas circunstancias.

. Problema

La mayoría de las aplicaciones de la plataforma J2EE tienen un requerimiento de búsqueda y consulta para buscar y listar ciertos datos. En algunos casos, dichas operaciones de búsqueda y consulta podrían traer resultados que pueden ser bastante grandes. No es práctico devolver toda la hoja de resultados cuando los requerimientos del cliente son moverese por los resultados, en vez de procesar el conjunto completo. Normalmente, un cliente usa los resultados de una consulta para propósitos de sólo-lectura, como mostrar una lista de resultados. Muchas veces el cliente sólo ve los primeros registros que devuelve la búsqueda, y podría descargar los registros restantes e intentar otra nueva consulta. La práctica de obtener uns lista de valores representados en un bean de entidad llamando al método ejbFind(), que devuelve una collection de objetos remotos, y luego llamar a cada bean de entidad para obtener el valor, consume muchos recursos de red y se considera una mala práctica.

Hay algunas consecuencias asociadas con el uso de los métodos búscadores de EJB que resultan en grandes conjuntos de datos. Cada implementación de contenedor tiene una cierta cantidad de métodos búscadores para crear una colección de referencias EJBObject. El rendimiento del método de búsqueda varía, dependiendo de la implementación del contenedor. De acuerdo a la especificación EJB, un contenedor podría invocar a métodos ejbActivate() sobre entidades encontradas con los métodos de búsqueda. Como mínimo, un método de búsqueda devuelve las claves primarias de las entidades encontradas, que el contenedor devuelve al cliente como una colección de referencias EJBObject. Este comportamiento se aplica para todas las implementaciones de contenedores. Algunas implementaciones podrían introducir una sobrecarga de métodos de búsqueda asociando los ejemplares de beans de entidad a esos ejemplares EJBObject para darle acceso al cliente a esos beans de entidad. Sin embargo, este es un uso pobre de los recursos si el cliente no está interesado en acceder al bean o en invocar sus métodos. Esta sobrecarga puede impedir el rendimiento de la aplicación si ésta incluye consultas que producen muchos resultados.

. Causas

  • La aplicación cliente necesita una facilidad de consulta eficiente para evitar tener que llamar al método ejbFind() de cada bean e invocar a cada objeto remoto devuelto.
  • Se necesita una mecanismo de caché en la capa-servidor para servir a los clientes que no pueden recibir y procesar el cojunto de resultados completo.
  • Se puede optimizar una consulta que se ejecuta repetidamente sobre unos datos razonablemente estáticos para proporcionar resultados más rápidos. Esto depende de la aplicación y de la implementación de este patrón.
  • Los métodos de búsqueda EJB no son apropiados para navegar por tablas enteras en la bases de datos o para buscar grandes conjuntos de resultados en una tabla.
  • Los métodos de búsqueda se podrían considerar sobrecargados cuando se utilizan para encontrar grandes cantidades de resultados. El contenedor podría crear un gran número de objetos de infraestructura para facilitar las búsquedas.
  • Los métodos de búsqueda EJB no sin apropiados para realizar caché de resultados. El cliente podría no ser capaz de manejar el conjunto completo de resultados en una sóla llamada. Si es así, el cliente podría necesitar un caché en el lado del cliente y funciones de navegación para moverese por el conjunto de resultados.
  • Los métodos de búsqueda EJB tiene consultas predeterminadas y ofrecen una flexibilidad mínima. La especificación EJB 2.0 permite un lenguaje de consulta, EJB QL, para beans de entidad manejados por el contenedor. EJB QL hace más fácil escribir métodos de búsqueda portables y ofrece una mayor flexibilidad.
  • El cliente quiere moverse hacia adelante o hacia atrás dentro de la hoja de resultados.

. Solución

Utilizar un Value List Handler para controlar la búsqueda, hacer un caché con los resultados, y proporcionar los resultados al cliente en una hoja de resultados cuyo tamaño y desplazamiento cumpla los requerimientos del cliente.

Este patrón crea un ValueListHandler para controlar la funcionalidad de la ejecución de la consulta y el caché de resultados. El ValueListHandler accede directamente a un DAO que puede ejecutar la consulta requerida. El ValueListHandler almacena los resultados obtenidos del DAO como una colección de Transfer Objects. El cliente le pide al ValueListHandler que proporcione resultados de la consulta según los necesite. El ValueListHandler implementa un patrón Iterator [GoF] para proporcionar la solución.

. Estructura

La siguiente figura muestra el diagrama de clases para el patrón Value List Handler:

. Participantes y Colaboraciones

La siguiente figura muestra el diagrama de secuencia del patrón Value List Handler:

. ValueListIterator

Este interface podría proporcionar la facilidad de iteración con los siguientes métodos de ejemplo:

  • getSize() obtiene el tamaño de la hoja de resultados.
  • getCurrentElement() obtiene el Transfer Object actual de la lista.
  • getPreviousElements(int howMany) obtiene una colección de Transfer Objects que son anteriores en la lista al elemento actual.
  • getNextElements(int howMany) obtiene una colección de Transfer Objects que son posteriores en la lista al elemento actual.
  • resetIndex() reinicia el índice para ir al inicio de la lista.

Dependiendo de las necesidades, se pueden incluir otros métodos de conveniencia en el interface ValueListIterator.

. ValueListHandler

Este es el objeto que implementa el interface ValueListIterator. ValueListHandler ejecuta la consulta requerida cuando se lo solicita el cliente. Obtiene los resultados de la consulta, que maneja en una colección privada representada por el objeto ValueList. ValueListHandler crea y manipula la colección ValueList. Cuando el cliente solicita los resultados, ValueListHandler obtiene los Transfer Objects desde el ValueList cacheado, crea una nueva colección de Transfer Objects, serializa la colección y la envía de vuelta alcliente. ValueListHandler también sigue la pista del índice actual y del tamaño de la lista.

. DataAccessObject

ValueListHandler puede hacer uso de un DataAccessObject para mantener separada la implementación del acceso a la base de datos. DataAccessObject proporciona un API sencillo para acceder a la base de datos (o cualquier otro almacenamiento persistente), ejecuta consultas y recupera resultados.

. ValueList

ValueList es una colección (una lista) que contiene los resultados de la consulta. Los resultados se almacenan como objetos Transfer Objects. Si falla la consulta y no se devuelven resultados, entonces esta lista está vacía. El bean de sesión ValueListHandler puede almacenar ValueList para evitar repeticiones innecesarias de la consulta.

. TransferObject

TransferObject representa una vista de un registro individual de los resultados de la consulta. Es un objeto serializable no modificable que proporciona un espacio para los datos de los atributos de cada registro.

. Estrategias

. Java Object

Se puede implementar el ValueListHandler como un objeto Java arbitario. En este caso, el ValueListHandler puede ser utilizado por cualquier cliente que necesite esa funcionalidad. Para aplicaciones que no usan beans enterprise, esta estrategia es muy útil. Por ejemplo se podría construir aplicaciones sencillas utilizando servlets, JSPs, Business Delegates, y DAOs. En este escenario, el Business Delegates puede utilizar un ValueListHandler implementado como un objeto Java para obtener una lista de valores.

. Stateful Session Bean

Cuando una aplicación utiliza beans enterprise en la capa de negocio, se podría preferir implementar un bean de sesión que utilice el ValueListHandler. En este caso, el bean de sesión simplemente se enfrenta a un ejemplar de ValueListHandler. Así, el bean de sesión se podría implementar como un bean de sesión con estado para contener la lista y su estado, y esto simplemente podría actúar como una fachada o como un proxy.

. Consecuencias

  • Proporciona Alternativas a los métodos find() de EJB para Grandes Consultas
    Normalmente, un método de búsqueda EJB es una forma cara de obtener una lista de ítems, ya que implica un número de referencias EJBObject. Value List Handler implementa un bean de sesión que utiliza un DAO para realizar la consulta y para proporcionar una colección de Transfer Objects que cumplen el criterio de búsqueda. Como los Transfer Objects tienen poca sobrecarga en comparación con las referencias EJBObject y su infraestructura asociada, este patrón proporciona beneficios cuando las aplicaciones clientes requieren grandes cantidades de resultados.
  • Crea un Caché de Resultados de la Consulta en el Lado del Servidor
    Se necesita cachear los resultados obtenidos de la ejecución de la consulta cuando un cliente debe mostrarlos en pequeñas partes en vez de una gran lista. Sin embargo, no todos los clientes basados en navegador puede realizar dicho caché. Cuando no pueden, el servidor debe proporcionar esta funcioalidad. El patrón Value List Handler proporciona una facilidad de caché en el bean de sesión para contener los resultados de la consulta. El conjunto de resultados es una colección de Transfer Objects que se puede serializar si es necesario.
    Cuando el cliente solicita una colección, o un subconjunto de una colección, el baen manejador devuelve los resultados solicitados como una colección serializada de Transfer Objects. El cliente recibe la colección y ahora tiene una copia local de la información, que el cliente puede mostrar o procesar. Cuando el cliente necesita un subconjunto adicional de resultados, le solicita al manejador que devuelva otra colección serializada que contenga los resultados necesarios. El cliente puede procesar la consulta en trozos más pequeños y manejables. El bean manejador también le proporciona al cliente facilidades de navegación (anterior y siguiente) para que pueda moverse por la lista de la forma necesaria.
  • Proporciona una Mayor Flexibilidad de Consulta
    Añadir una nueva consulta podría requerir la creación de un nuevo método finder o modificar uno existente, especialmente cuando se utilizan beans de entidad manejados por el bean (con beans de entidad manejados por el bean, el desarrollador implementa los métodos de búsqueda en la implementación del bean). Con un bean de entidad manejado por el contenedor, el desarrollador especifica los métodos finder del bean de entidad en el descriptor de despliegue del bean. Los cambios en una consulta para bean manejado por el contenedor requieren cambios en el descriptor de despliegue. Por lo tanto, estos métodos no son muy adecuados cuando los requerimientos de la consulta cambian dinámicamente. Podemos implementar un Value List Handler para que sea más flexible que los métodos del EJB proporcionado facilidades de consultas dinámicas, construyendo los argumentos de la consulta en el momento de la ejecución utilizando plantillas de métodos, etc. En otras palabras, un desarrollador de un Value List Handler puede implementar búsqueda inteligente y algoritmos de caché sin verse limitado por los métodos finder.
  • Mejora el Rendimiento de Red
    El rendimiento de la red se ve mejorado porque sólo los datos solicitados, en vez de todos los datos, se envían (serializados) al cliente sobre unas necesidades básicas. Si el cliente muestra los primeros resultados y luego abandona la consulta, no se ha ocupado el ancho de banda de la red, ya que los datos se almacenan en el servidor y nunca se han envíado al cliente. Sin embargo, si el cliente procesa todos los resultados, hace varias llamadas remotas al servidor. Cuando el cliente conoce por adelantado que necesita todos los resultados, el bean manejador puede proporcionar un método que los envíe al cliente en una sola llamada a método, y no se utiliza el caché.
  • Permite Atrasar las Transaciones del Bean de Entidad
    El caché de los resultados en el lado del servidor permite minimizar la sobrecarga de la búsqueda y podría mejorar el control de transaciones. Cuando el cliente está listo para procesar un bean de entidad, accede al bean dentro de un contexto de transación definido por el caso de utilización. Por ejemplo, una consulta para mostrar una lista de libros utiliza un Value List Handler para obtener la lista. Cuando el usuario quiere ver los detalles de un libro, implica al bean de entidad del libro en la transación.

. Código de Ejemplo

. Implementar el Value List Handler como un objeto Java

Consideremos un ejemplo donde se va a recuperar y mostrar una lista de objetos de negocio de un Proyecto. En este caso se puede aplicar el patrón Value List Handler. En el siguiente ejemplo tenemos la clase ProjectListHandler, que es responsable de proporcionar la lista de proyectos. Esta clase extiende la clase base ValueListHandler, que proporciona la funcionalidad de iteración genéricoa para todas las implementaciones de Value List Handler de esta aplicación.


package corepatterns.apps.psa.handlers;

import java.util.*;
import corepatterns.apps.psa.dao.*;
import corepatterns.apps.psa.util.*;
import corepatterns.apps.psa.core.*;

public class ProjectListHandler
extends ValueListHandler {

  private ProjectDAO dao = null;
  // use ProjectTO as a template to determine
  // search criteria
  private ProjectTO projectCriteria = null;

  // Client creates a ProjectTO instance, sets the
  // values to use for search criteria and passes
  // the ProjectTO instance as projectCriteria
  // to the constructor and to setCriteria() method
  public ProjectListHandler(ProjectTO projectCriteria)
  throws ProjectException, ListHandlerException {
    try {
      this.projectCriteria = projectCriteria;
      this.dao = PSADAOFactory.getProjectDAO();
      executeSearch();
    } catch (Exception e) {
      // Handle exception, throw ListHandlerException
    }
  }

  public void setCriteria(ProjectTO projectCriteria) {
    this.projectCriteria = projectCriteria;
  }

  // executes search. Client can invoke this
  // provided that the search criteria has been
  // properly set. Used to perform search to refresh
  // the list with the latest data.
  public void executeSearch()
  throws ListHandlerException {
    try {
      if (projectCriteria == null) {
        throw new ListHandlerException(
          "Project Criteria required...");
      }
      List resultsList =
        dao.executeSelect(projectCriteria);
      setList(resultsList);
    } catch (Exception e) {
      // Handle exception, throw ListHandlerException
    }
  }
}

En el siguiente código tenemos la clase ValueListHandler que implementa el interface del iterador genérico ValueListIterator, que veremos en siguientes listados.


package corepatterns.apps.psa.util;

import java.util.*;

public class ValueListHandler
implements ValueListIterator {

  protected List list;
  protected ListIterator listIterator;

  public ValueListHandler() {
  }

  protected void setList(List list)
  throws IteratorException {
    this.list = list;
    if(list != null)
      listIterator =  list.listIterator();
    else
      throw new IteratorException("List empty");
  }

  public Collection getList(){
    return list;
  }

  public int getSize() throws IteratorException{
    int size = 0;

    if (list != null)
      size = list.size();
    else
      throw new IteratorException(...); //No Data

    return size;
  }

  public Object getCurrentElement()
  throws IteratorException {

    Object obj = null;
    // Will not advance iterator
    if (list != null)
    {
      int currIndex = listIterator.nextIndex();
      obj = list.get(currIndex);
    }
    else
      throw new IteratorException(...);
    return obj;

  }

  public List getPreviousElements(int count)
  throws IteratorException {
    int i = 0;
    Object object = null;
    LinkedList list = new LinkedList();
    if (listIterator != null) {
      while (listIterator.hasPrevious() && (i < count)){
        object = listIterator.previous();
        list.add(object);
        i++;
      }
    }// end if
    else
      throw new IteratorException(...); // No data

    return list;
  }

  public List getNextElements(int count)
  throws IteratorException {
    int i = 0;
    Object object = null;
    LinkedList list = new LinkedList();
    if(listIterator != null){
      while(  listIterator.hasNext() && (i < count) ){
        object = listIterator.next();
        list.add(object);
        i++;
      }
    } /  / end if
    else
      throw new IteratorException(...); // No data

    return list;
  }

  public void resetIndex() throws IteratorException{
    if(listIterator != null){
      listIterator = list.ListIterator();
    }
    else
      throw new IteratorException(...); // No data
  }
  ...
}

Abajo tenemos el código importante para acceder al objeto ProjectDAO, utilizado por ValueListHandler para ejecutar la consulta y obtener los resultados.


package corepatterns.apps.psa.dao;

public class ProjectDAO {
  final private String tableName = "PROJECT";

  // select statement uses fields
  final private String fields = "project_id, name," +
      "project_manager_id, start_date, end_date, " +
      " started, completed, accepted, acceptedDate," +
      " customer_id, description, status";

  // the methods relevant to the ValueListHandler
  // are shown here.
  // See Data Access Object pattern for other details.
  ...
  private List executeSelect(ProjectTO projCriteria)
  throws SQLException {

    Statement stmt= null;
    List list = null;
    Connection con = getConnection();
    StringBuffer selectStatement =   new StringBuffer();
    selectStatement.append("SELECT "+ fields +
          " FROM " + tableName + "where 1=1");

    // append additional conditions to where clause
    // depending on the values specified in
    // projCriteria
    if (projCriteria.projectId != null) {
      selectStatement.append (" AND PROJECT_ID = '" +
        projCriteria.projectId + "'");
    }
    // check and add other fields to where clause
    ...

    try {
      stmt = con.prepareStatement(selectStatement);
      stmt.setString(1, resourceID);
      ResultSet rs = stmt.executeQuery();
      list = prepareResult(rs);
      stmt.close();
    }
    finally {
      con.close();
    }
    return list;
  }

  private List prepareResult(ResultSet rs)
  throws SQLException {
    ArrayList list = new ArrayList();
    while(rs.next()) {
      int i = 1;
      ProjectTO proj = new
        ProjectTO(rs.getString(i++));
      proj.projectName = rs.getString(i++);
      proj.managerId = rs.getString(i++);
      proj.startDate = rs.getDate(i++);
      proj.endDate = rs.getDate(i++);
      proj.started = rs.getBoolean(i++);
      proj.completed = rs.getBoolean(i++);
      proj.accepted = rs.getBoolean(i++);
      proj.acceptedDate = rs.getDate(i++);
      proj.customerId = rs.getString(i++);
      proj.projectDescription = rs.getString(i++);
      proj.projectStatus = rs.getString(i++);
      list.add(proj);

    }
    return list;
  }
  ...
}

Código de ejemplo de la clase ValueListIterator:


package corepatterns.apps.psa.util;

import java.util.List;

public interface ValueListIterator {

  public int getSize()
    throws IteratorException;

  public Object getCurrentElement()
    throws IteratorException;

  public List getPreviousElements(int count)
    throws IteratorException;

  public List getNextElements(int count)
    throws IteratorException;

  public void resetIndex()
    throws IteratorException;

  // other common methods as required
  ...
}

. Patrones Relacionados

  • Iterator [GoF]
    El patrón Value List Handler está basado en el patrón Iterator, descrito en el libro de Gof: Design Patterns: Elements of Reusable Object-Oriented Software.
  • Session Facade
    Como el Value List Handler es un bean de sesión, podría aparecer como un Session Facade especializado. Sin embargo, aisladamente, es un bean de sesión especializado en vez de un Session Facade. Un Session Facade tiene otras motivaciones y características y es mucho más genérico.
 
Patrocinados
 

Copyright © 1999-2007 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network

red internet: musica mp3 | logos y melodias | hospedaje web linux | registro de dominios | servidores dedicados
más internet: comprar | recursos gratis | posicionamiento en buscadores | tienda virtual | gifs animados