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

Las aplicaciones cliente necesitan intercambiar datos con Beans Enterprise.

.�Problema

Las aplicaciones de la plataforma J2EE implementan componentes de negocio del lado del servidor como beans de sesi�n y de entidad. Algunos m�todos expuestos por los componentes de negocio devuelven datos al cliente. Algunas veces, el cliente invoca a los m�todos get de un objeto de negocio varias veces para obtener todos los valores de los atributos.

Los beans de sesi�n representan los servicios de negocio y no se comparten entre usuarios. Un bean de sesi�n proporciona m�todos de servicios gen�ricos cuando se implementan para el patr�n Session Facade.

Por otro lado, los beans de entidad, son objetos transacionales, multiusuario que representan datos persistentes. Un bean de entidad expone los valores de los atributos proporcionando un m�todo accesor (tambi�n referidos como m�todos get) por cada atributo que desea exponer.

Toda llamada a m�todo hecha al objeto de servicio de negocio, ya sea a un bean de entidad o a un bean de sesi�n, potencialmente es una llamada remota. As�, en una aplicaci�n de JavaBeans Enterprise (EJB) dichas llamadas remotas usan la capa de red sin importar la proximidad del cliente al bean, creando una sobrecarga en la red. Las llamadas a m�todos de beans enterprise podr�a penetrar las capas de red incluso si tanto el cliente como el contenedor EJB que mantiene el bean de entidad se est�n ejecutando en la misma JVM (M�quina Virtual Java), el mismo Sistema Operativo o m�quina f�sica. Algunos vendedores podr�an implementar mecanismos para reducir esta sobrecarga utilizando una aproximaci�n de acceso m�s directa pasando por encima de la red.

Seg�n se incrementa la utilizaci�n de estos m�todos remotos, el rendimiento de la aplicaci�n se puede degradar significativametne. Por lo tanto, utilizar varias llamadas a m�todos get que devuelven simples valores de atributos es ineficiente para obtener valores de datos desde un bean enterprise.

.�Causas

  • Todos los accesos a un bean enterprise se realizan mediante interfaces remotos. Cada llamada a un bean enterprise potencialmente es una llamada a un m�todo remoto con sobrecarga de red.
  • Normalmente, las aplicaciones tienen transaciones de lectura con mayor frecuencia que las de actualizaci�n. El cliente solicita los datos desde la capa de negocio para su presentaci�n, y otros tipos de procesamientos de s�lo-lectura. El cliente actualiza los datos de la capa de negocio con mucha menos frecuencia con la que los lee.
  • El cliente normalmente solicita valores que son algo m�s que un atributo o que son dependendientes del objeto de un bean enterprise. As�, el cliente podr�a invocar varias llamadas remotas para obtener los datos necesarios.
  • El n�mero de llamadas que un cliente hace al bean enterprise impactan en el rendimiento de la red. Las aplicaciones charlatanas -- aquellas que incremenetan el trafico entre las capas del cliente y del servidor -- suelen degradar el rendimiento de la red.

.�Soluci�n

Utilizar un Transfer Object para encapsular los datos de negocio. Se utiliza una �nica llamada a un m�todo para env�ar y recuperar el Transfer Object. Cuando el cliente solicita los datos de negocio al bean enterprise, �ste puede construir el Transfer Object, rellenarlo con sus valores de atributos y pasarlo por valor al cliente.

Los clientes normalmente solicitan m�s de un valor a un bean enterprise. Para reducir el n�mero de llamadas remotas y evitar la sobrecarga asociada, es mejor el Transfer Objects para transportar los datos desde el bean enteprise al cliente.

Cuando un bean enterprise utiliza un Transfer Object, el cliente hace una sola llamada a un m�todo remoto del bean enterprise para solicitar el Transfer Object en vez de numerosas llamadas remotas para obtener valores de atributos individuales. Entonces el bean enterprise construye un nuevo ejemplar Transfer Object, copia dentro los valores del objeto y lo devuelve al cliente. El cliente recibe el Transfer Object y puede entonces invocar los m�todos accesores (o get) del Transfer Object para obtener los valores de atributos individuales del objeto Transfer Object. O, la implementaci�n del Transfer Object podr�a hacer que todos los atributos fueran p�blicos. Como el Transfer Object se pasa por valor al cliente, todas las llamadas al ejemplar Transfer Object son llamadas locales en vez de invocaciones de m�todos remotos.

.�Estructura

Ls siguiente figura muestra el diagrama de clases que representa el patr�n Transfer Object en su forma m�s simple:

Como se ve en este diagrama de clases, el Transfer Object lo construye bajo pedido el bean enterprise y lo devuelve al cliente remoto. Sin embargo, el patr�n Transfer Object puede adoptar varias estrategias, dependendiendo de los requerimientos.

.�Participantes y Responsabilidades

La siguiente figura contiene el diagrama de secuencia que muestra las interacciones del patr�n Transfer Object:

.�Client

Representa al cliente del bean enterprise. El cliente puede ser una aplicaci�n final de usuario, como es el caso de una aplicaci�n que ha sido dise�ada para acceder directamente a beans enterprise. El cliente puede utilizar Business Delegate u otro BusinessObject diferente.

.�BusinessObject

Representa un rol en este patr�n que puede cumplir un bean de sesi�n, un bean de entidad, o un Data Access Object (DAO). BusinessObject es el responsable de crear el Transfer Object y devolverlo al cliente bajo pedido. El BusinessObject tambi�n podr�a recibir datos desde el cliente en la forma de un Transfer Object y utilizar esos datos para realizar una actualizaci�n.

.�TransferObject

TransferObject es un objeto Java serializable referenciado como un Transfer Object. Una clase Transfer Object podr�a proporcionar un constructor que acepte todos los atributos requeridos para crear el Transfer Object. El constructor podr�a aceptar todos los valores de atributos del bean de entidad para el que se ha dise�ado el Transfer Object. Normalmente, los miembros del Transfer Object se definen como p�blicos, as� eliminan la necesidad de los m�todos get y set. Si se necesita alguna protecci�n, los miembros podr�an definirse como protected o private, y se definir�an m�todos get para sus valores. Si no ofrece m�todos set para los valores, un Transfer Object est� protegido frente a modificaciones despu�s de su creaci�n. Si s�lo se permite la modificaci�n de unos pocos miembros para facilitar las actualizaciones, entonces si que se de deben proporcionar m�todos set. Por lo tanto, la creacci�n del Transfer Object var�a dependiendo de los requerimientos de la aplicaci�n.

.�Estrategias

Las dos primeras estrategias sen aplican cuando el bean enterprise se implementa como un bean de sesi�n o un bean de entidad.

Las estrategias posteriores son aplicables s�lo cuando el BusinessObject se iplementa como un bean de entidad.

.�Updatable Transfer Objects

En esta estrategia, el Transfer Object no s�lo lleva los valores desde el BusinessObject hasta el cliente, tambi�n lleva los cambios realizados por el cliente de vuelta al objeto de negocio.

La siguiente figura es un diagrama de clases que muestra las relaciones entre el BusinessObject y el Transfer Object:

El BusinessObject crea el Transfer Object. Recuerda que un cliente podr�a necesitar aceder a los valores del BusinessObject no s�lo para leerlos sino tambi�n para modificarlos. Para que el cliente pueda modificar los valores de los atributos del BusinessObject, �ste debe proporcionar m�todos mutadores. A �stos m�todos tambi�n se les conoce como m�todos set.

En lugar de proporcionar m�todos set especificos para cada atributo, lo que resultar�a en una sobrecarga de la red, el BusinessObject puede exponer un m�todo setData() gen�rico que acepta un objeto Transfer Object como argumento. El Transfer Object pasado a este m�todo contiene los valores actualizados por el cliente. Como el Transfer Object tiene que ser mutable, su clase tiene que proporcionar m�todos set para todos los atributos que pueda modificar el cliente. Los m�todos set del objeto Transfer Object pueden incluir validaciones a nivel de campo y chequeos de integridad si son necesarios. Una vez que el cliente obtiene un Transfer Object desde el BusinessObject, puede invocar localmente los m�todos set necesarios para cambiar los valores de los atributos. Dichos cambios locales no impactan en el objeto BusinessObject hasta que se llame al m�todo setData().

El m�todo setData() serializa la copia que tiene el cliente del Transfer Object y la env�a al BusinessObject. El BusinessObject recibe el Transfer Object modificado desde el cliente y mezcla los cambios con sus propios atributos. La operacion de mezcla podr�a complicar el dise�o del BusinessObject y del Transfer Object; la secci�n sobre "Consecuencias" discute estas potenciales complicaciones. Una estrategia a utilizar aqu� es actualizar s�lo los atributos que han cambiado, en vez de actualizar todos los atributos. Una bandera de 'cambiado' situada en el Transfer Object se podr�a utilizar para determinar los atributos a actualizar, en vez de hacer una comparaci�n directa.

Hay un impacto en el dise�o cuando se usa esta estrategia en t�rminos de propagaci�n de actualizaci�n, sincronizaci�n y control de versi�n.

La siguiente figura muestra el diagram para toda la interacci�n de actualizaci�n:

.�Multiple Transfer Objects

Algunos objetos de negocio de las aplicaciones pueden ser muy complejos. En dichos casos, es posible que un s�lo objeto de negocio produzca diferentes Transfer Objects, dependiendo de la petici�n del cliente. Existe una relaci�n uno-a-muchos entre el objeto de negocio y los muchos Transfer Objects que puede producir. En estas circunstancias debemos considerar la utilizaci�n de esta estrategia.

Por ejemplo, cuando el objeto de negocio se implementa como un bean de sesi�n, normalmente aplicando el patr�n Session Facade, el bean podr�a interact�ar con numerosos componentes de negocio para proporcionar el servicio. El bean de sesi�n produce su Transfer Object desde diferentes fuentes. De forma similar, cuando se implementa el BusinessObject como un bean de entidad gen�rico, normalmente aplicando el patr�n Composite Entity, el bean de entidad tendr� relaciones complejas con varios objetos dependientes. En ambos casos, es una buena pr�ctica proporcionar mecanismos para producir Transfer Objects que realmente representen a partes de los componentes gen�ricos.

Por ejemplo, en una aplicaci�n tradicional, un Composite Entity que representa la cartera de un cliente puede ser un componente gen�rico muy complejo que puede producir Transfer Objects que proporcionen datos de las partes de la cartera, como informaci�n del cliente, lista de stocks, etc. Un ejemplo similar es un bean de sesi�n que maneja clientes y que proporciona servicios interactuando con otros muchos BusinessObjects y otros componentes para proporcionar su servicio. El bean controlador de clientes puede producir peque�os Transfer Objects, como direcciones de clientes, lista de contactos, etc., para representar partes de su modelo.

Para �mbos escenarios, es posible adoptar y aplicar la estrategia Multiple Transfer Objects para que los componentes de negocio, tanto si son beans de sesi�n como de entidad, puedan crear varios tipos de Transfer Objects. En esta estrategia, la entidad de negocio proporciona varios m�todos para obtener diferentes Transfer Objects. Cada uno de esos m�todos crea y devuelve un tipo diferente de Transfer Object. En la siguiente figura podemos ver el diagrama de clases para esta estrategia.

Cuando un cliente necesita un Transfer Object del tipo TransferObjectA, lama al m�todo getDataA() de la entidad, pidiendo un TransferObjectA. Cuando necesita un Transfer Object del tipo TransferObjectB, llama al m�todo getDataB() de la entidad, pidiendo un TransferObjectB, etc. Esto se puede ver en la siguiente figura:

.�Entity Inherits Transfer Object

Cuando el BusinessObject se implementa como un bean de entidad y los clientes normalmente necesitan acceder a todos los datos del bean de entidad, entonces el bean de entidad y el Transfer Object tienen los mismos atributos. En este caso, como existe una relaci�n uno-a-uno entre el bean de entidad y su Transfer Object, el bean de entidad podr�a ser capaz de utilizar la herencia para evitar la duplicaci�n de c�digo.

En esta estrategia, el bean de entidad extiende (o desdeciende de) la clase del Transfer Object. La �nica asumpci�n es que el bean de entidad y el Transfer Object comparten las mismas definiciones de atributos. En la siguiente figura podemos ver el diagrama de clases para esta estrategia:

El TransferObject implementa uno o m�s m�todos getData() como explicamos en la estrategia anterior. Cuando el bean de entidad desciende de esta clase Transfer Object, el cliente invoca un m�todo getData() heredado del bean de entidad para obtener un Transfer Object.

As�, esta estrategia elimina la duplicaci�n de c�digo entre el bean de entidad y el Transfer Object. Tambi�n ayuda a manejar los cambios en los requerimientos del Transfer Object aislando los cambios de la clase Transfer Object y previniendo que los cambios afecten al bean de entidad.

Esta estrategia tiene un inconveniente relacionado con la herencia. Si el Transfer Object se comparte a trav�s de su herencia, los cambios que se hagan en la clase Transfer Object afectar�n a todas sus subclases, obligando potencialmente a modificar toda su descendencia. El diagrama de secuencia de la siguiente figura demuestra esta estrategia:

En la secci�n de C�digo de Ejemplo veremos esta implementaci�n.

.�Transfer Object Factory

La estrategia Entity Inherits Transfer Object se puede extender para que un bean de entidad soporte m�ltiples Transfer Objects empleando una factor�a de Transfer Object para crear Transfer Objects bajo demanda utilizando reflection. Esto resulta en una estrategia a�n m�s din�mica para la creaci�n de Transfer Object.

Para conseguir esto, definimos un interface diferente para cada tipo de Transfer Object que se debe devolver. La implementaci�n que hace el bean de entidad de la superclase de Transfer Object debe implementar todos esos interfaces. Adem�s, debemos crear una clase separada para implementar todos los interfaces definidos, como se muestra en el diagrama de clases de la siguiente figura.

Una vez que se han definido e implementado todos los interfaces, creamos un m�todo en la clase TransferObjectFactory al que se le pasan dos argumentos:

  • El ejemplar del bean de entidad para el que se debe crear el Transfer Object.
  • El interface que identifica el tipo de Transfer Object a crear.

Entonces el TransferObjectFactory puede ejemplarizar un objeto de la clase correcta, configurar sus valores, y devolver el ejemplar de Transfer Object recientemente creado.

En la siguiente figura podemos ver el diagrama de secuencia para esta estrategia:

El cliente le solicita un Transfer Object al BusinessEntity. �ste le pasa la clase del objeto Transfer Object requerido a TransferObjectFactory, que crea un nuevo Transfer Object de esa clase dada. El TransferObjectFactory usa reflection para obtener din�micamente la informaci�n de clase para la clase del Transfer Object y construir un nuevo ejemplar. La obtenci�n de los valores para el BusinessEntity que realiza el TransferObjectFactory se consigue utilizando invocaci�n din�mica.

Estos son los beneficios de aplicar la estrategia Transfer Object Factory:

  • Se tiene que escribir menos c�digo para crear Transfer Objects.
  • La misma factor�a de clases Transfer Object puede ser reutilizada por diferentes beans enterprise.
  • Cuando cambia la definici�n de una clase Transfer Object, la factor�a de objetos Transfer Object maneja estos cambios sin ning�n esfuerzo de codificaci�n adicional.
  • Esto incrementa la manejabilidad y es menos propenso a errores cuando se cambian las definiciones del Transfer Object.

La estrategia Transfer Object Factory tiene las siguienes consecuencias:

  • Esta basada en el hehco de que la implementaci�n del bean enterprise extiende (desciende) de la clase general Transfer Object.
  • El Transfer Object general necesita implementar todos los interfaces definidos para diferentes Transfer Objects que se necesiten suministar al bean de entidad.
  • Se deben cumplir las convenciones de nombrado para poder hacer que esta estrategia funcione.
  • Como se utiliza reflection para inspeccionar y construir din�micamente Transfer Objects, hay una ligera p�rdida de rendimiento en su construcci�n.Sin embargo, si se considera el tiempo total de comunicaci�n, dicha p�rdida es m�nima en su comparaci�n.

Hay un inconveniente asociado con esta estrategia. Su poder y flexibilidad se deben sopesar en comparaci�n con la sobrecarga de rendimiento asociada con la utilizaci�n de reflection en tiempo de ejecuci�n.

.�Consecuencias

  • Simplifica el Bean de Entidad y el Interface Remoto
    El bean de entidad proporciona un m�todo getData() para obtener el Transfer Object que contiene los valores de los atributos. Esto podr�a eliminarse implementando m�ltiples m�todos get en el bean y defini�ndolos en el interface remoto del bean. De forma similar, si el bean de entidad proporciona un m�todo setData() para actualizar los valores de atributos del bean de entidad con una sola llamada a m�todo, se podr�a eliminar implementando varios m�todos set en el bean.
  • Transfiere M�s Datos en Menos Llamadas Remotas
    En lugar de realizar m�ltiples llamadas sobre la red al BusinessObject para obtener los valores de los atributos, esta soluci�n proporciona una sola llamada a un m�todo. Al mismo tiempo, esta �nica llamada obtiene una mayor cantidad de datos. Cuando consideremos la utilizaci�n de este patr�n, debemos tener en cuenta el inconveniente dee el menor n�mero de lamadas contra la mayor transmisi�n de datos por cada llamada. Alternativamente, podemos proporcionar �mbos tipos de m�todos: m�todos get y set espec�ficos y m�todos get y set gen�ricos. El desarrollador puede elegir la t�cnica apropiada seg�n sus requerimentos.
  • Reduce el Tr�fico de Red
    Un Transfer Object transfiere los valores desde el bean de entidad al cliente en una llamada a un m�todo remoto. El Transfer Object act�a como un transportista de datos y reduce el n�mero de llamadas remotas requeridas para obtener los valores de los atributos del bean; y esto significa un mejor rendimiento de la red.
  • Reduce la Duplicaci�n de C�digo
    Usando las estrategias Entity Inherits Transfer Object y Transfer Object Factory, es posible reducir o eliminar la duplicaci�n de c�digo entre el bean de entidad y el Transfer Object. Sin embargo, con el uso de la estrategia Transfer Object Factory, se podr�a incrementar la complejidad de la implementaci�n. Tambi�n hay un coste asociado a la p�rdida de rendimiento con esta estrategia al utilizar reflection din�micamente. En la mayor�a de los casos, la estrategia Entity Inherits Transfer Object podr�a ser suficiente para cumplir nuestras necesidades.
  • Podr�a Introducir Transfer Objects Obsoletos
    Adoptando la estrategia Updatable Transfer Objects se permite al cliente realizar modificaciones en la copia local del Transfer Object. Una vez que se han completado las modificaciones, el cliente puede invocar el m�todo setData() del bean de entidad y pasarle el Transfer Object modificado. El bean recibe las modificaciones y las mezcla con los valores que �l tiene. Sin embargo, podr�a haber un problema con Transfer Objects obsoletos. El bean de entidad actualiza sus valores, pero no tiene en cuenta si otros clientes han solicitado el mismo Transfer Object con anterioridad. Estos clientes podr�an contener en su copia local ejemplares de Transfer Object que no reflejan las copia real de los datos del bean. Como el bean no tiene en cuenta a estos clientes, es posible propagar la actualizaci�n de Transfer Objects obsoletos que mantienen otros clientes.
  • Podr�a Incrementar la Complejidad Debido a la Sincronizaci�n y el Control de Versi�n
    El bean de entidad mezcla los valores modificados con sus propios valores cuando los recibe en un Transfer Object de un cliente. Sin embargo, el bean debe manejar la situaci�n donde dos o m�s clientes simult�neamente solicitan actualizaciones conflictivas de los valores del bean. Permitir estas actualizaciones podr�a resultar en conflictos de datos. El control de versi�n es una forma de evitar estos conflictos. El bean de entidad puede incluir como uno de sus atributos un n�mero de versi�n o una fecha de �ltima-modificaci�n. Este n�mero de versi�n se copiar�a en el Transfer Object. Una transaci�n de actualizaci�n puede resolver conflictos utilizando el atributo del n�mero de versi�n. Si un cliente que contiene un Transfer Object obsoleto intenta actualizar el bean, �ste puede detectar el n�mero de versi�n obsoleto e informar al cliente de esta condici�n de error. Entonces el cliente tiene que obtener el �ltimo Transfer Object y reintentar la actualizaci�n. En casos extremos esto podr�a resultar en un cliente hambriento -- el cliente nunca puede terminar su actualizaci�n.
  • Accesos y Transaciones Concurrentes
    Cuando dos o m�s clientes acceden de forma concurrente al BusinessObject, el contenedor aplica la sem�ntica de transaciones de la arquitectura EJB. Si, para un bean entreprise, el nivel de aislamiento de transaciones se selecciona a TRANSACTION_SERIALIZED en el descriptor de despliegue, el contenedor proporciona la m�xima protecci�n a la transaci�n y se asegura de su integridad. Por ejemplo, supongamos que el flujo de trabajo para la primera transaci�n implica obtener un Transfer Object, luego el proceso cont�nua modificando el objeto BusinessObject. La segunda transaci�n, como se han aislado las transaciones serializadas, obtendr� el Transfer Object con los valores correctos (los m�s actualizados). Sin embargo, para transaciones con menos restricciones, la protecci�n es menos r�gida, permitiendo inconsistencias en el Transfer Objects por accesos concurrentes. Adem�s, tendremos que tratar con problemas relacionados con la sincronizaci�n, el control de versi�n y los Transfer Objects obsoletos.

.�C�digo de Ejemplo

.�Implementar el patr�n Transfer Object

Consideremos un ejemplo donde se ha modelado un objeto de negocio llamado Project y se ha implementado como un bean de entidad. El bean de entidad Project necesita enviar datos a sus clientes en un Transfer Object cuando el cliente llame al m�todo getProjectData(). Abajo podemos ver el c�digo de la clase Transfer Object para este ejemplo, ProjectTO:

 
// Transfer Object to hold the details for Project
public class ProjectTO implements java.io.Serializable {
    public String projectId;
    public String projectName;
    public String managerId;
    public String customerId;
    public Date startDate;
    public Date endDate;
    public boolean started;
    public boolean completed;
    public boolean accepted;
    public Date acceptedDate;
    public String projectDescription;
    public String projectStatus;

    // Transfer Object constructors...
}
]>>
</codigo>

<para>
Abajo podemos ver el c�digo para el bean de entidad de este ejemplo:
</para>
<codigo>
<![CDATA[
...
public class ProjectEntity implements EntityBean {
    private EntityContext context;
    public String projectId;
    public String projectName;
    public String managerId;
    public String customerId;
    public Date startDate;
    public Date endDate;
    public boolean started;
    public boolean completed;
    public boolean accepted;
    public Date acceptedDate;
    public String projectDescription;
    public String projectStatus;
    private boolean closed;

    // other attributes...
    private ArrayList commitments;
    ...

    // Method to get Transfer Object for Project data
    public ProjectTO getProjectData() {
      return createProjectTO();
    }

    // method to create a new Transfer Object and 
    // copy data from entity bean into the value 
    // object
    private ProjectTO createProjectTO() {
        ProjectTO proj = new ProjectTO();
        proj.projectId = projectId;
        proj.projectName = projectName;
        proj.managerId = managerId;
        proj.startDate = startDate;
        proj.endDate = endDate;
        proj.customerId = customerId;
        proj.projectDescription = projectDescription;
        proj.projectStatus = projectStatus;
        proj.started = started;
        proj.completed = completed;
        proj.accepted = accepted;
        proj.closed = closed;
        return proj;
    }
    ...
}

.�Implementar la Estrategia Updatable Transfer Objects

El ejemplo anterior se puede ampliar para implementar la estrategia Updatable Transfer Objects. En este caso, el bean de entidad deber�a proporcionar un m�todo setProjectData() para actualizar el bean de entidad pas�ndole un Transfer Object que contenga los datos utilizados para realizar la actualizaci�n. Abajo est� el c�digo para esta estrategia:


...
public class ProjectEntity implements EntityBean {
    private EntityContext context;
  ...
  // attributes and other methods as in Example 8.4
  ...

  // method to set entity values with a Transfer Object
  public void setProjectData(ProjectTO updatedProj) {
    mergeProjectData(updatedProj);
  }

  // method to merge values from the Transfer Object into
  // the entity bean attributes
  private void mergeProjectData(ProjectTO updatedProj) {
    // version control check may be necessary here 
    // before merging changes in order to 
    // prevent losing updates by other clients
    projectId = updatedProj.projectId;
    projectName = updatedProj.projectName;
    managerId = updatedProj.managerId;
    startDate = updatedProj.startDate;
    endDate = updatedProj.endDate;
    customerId = updatedProj.customerId;
    projectDescription                  = 
        updatedProj.projectDescription;
    projectStatus = updatedProj.projectStatus;
    started = updatedProj.started;
    completed = updatedProj.completed;
    accepted = updatedProj.accepted;
    closed = updatedProj.closed;
  }
  ...
}

.�Implementar la Estrategia Multiple Transfer Objects

Consideremos un ejemplo donde los clientes acceden a un bean de entidad Resource para pedirle diferentes Transfer Objects. El primer tipo de Transfer Object, ResourceTO, se utiliza para transferir datos de un peque�o conjunto de atributos. El segundo tipo de Transfer Object, ResourceDetailsTO, se usa para transferir datos de un conjunto mayor de atributos. El cliente puede utilizar el primer Transfer Object si s�lo necesita los datos b�sicos representados por ese Transfer Object, y puede utilizar el segundo si necesita informaci�n m�s detalla. Observa que esta estrategia se puede aplicar para producir dos o m�s Transfer Objects que contengan diferentes datos, y no s�lo a un subconjunto o un superconjunto como se muestra aqu�.

C�digo de ejemplo para el primer objeto Transfer Objects, ResourceTO:


// ResourceTO: This class holds basic information
// about the resource
public class ResourceTO implements 
  java.io.Serializable {
  public String resourceId;
  public String lastName;
  public String firstName;
  public String department;
  public String grade;
  ...
}

C�digo de ejemplo para el segundo objeto Transfer Objects, ResourceDetailsTO:


// ResourceDetailsTO This class holds detailed 
// information about resource
public class ResourceDetailsTO {
  public String resourceId;
  public String lastName;
  public String firstName;
  public String department;
  public String grade;
  // other data...
  public Collection commitments;
  public Collection blockoutTimes;
  public Collection skillSets;
}

C�digo del bean de entidad Resource:


// imports
...
public class ResourceEntity implements EntityBean {
  // entity bean attributes
  ...

  // entity bean business methods
  ...

  // Multiple Transfer Object method : Get ResourceTO
  public ResourceTO getResourceData() {

    // create new ResourceTO instance and copy
    // attribute values from entity bean into TO
    ...
    return createResourceTO();
  }

  // Multiple Transfer Object method : Get 
  // ResourceDetailsTO
  public ResourceDetailsTO getResourceDetailsData() {

    // create new ResourceDetailsTO instance and copy
    // attribute values from entity bean into TO
    ...
    return createResourceDetailsTO(); 
  }

  // other entity bean methods
  ...
}

C�digo de Ejemplo del cliente del bean de entidad:

 

...
  private ResourceEntity resourceEntity;
  private static final Class homeClazz =

  corepatterns.apps.psa.ejb.ResourceEntityHome.class;
  ...
  try {
    ResourceEntityHome home =
      (ResourceEntityHome)
        ServiceLocator.getInstance().getHome(
            "Resource", homeClazz);
        resourceEntity = home.findByPrimaryKey( 
                            resourceId);
  } catch(ServiceLocatorException ex) {
    // Translate Service Locator exception into
    // application exception
    throw new ResourceException(...);
  } catch(FinderException ex) {
    // Translate the entity bean finder exception into
    // application exception
    throw new ResourceException(...);
  } catch(RemoteException ex) {
    // Translate the Remote exception into
    // application exception
    throw new ResourceException(...);
  }
  ...
  // retrieve basic Resource data 
  ResourceTO vo = resourceEntity.getResourceData();
  ...
  // retrieve detailed Resource data
  ResourceDetailsTO =           
    resourceEntity.getResourceDetailsData();
  ...

.�Implementar la Estrategia Entity Inherits Transfer Object

Consideremos un ejemplo donde un bean de entidad, ContactEntity hereda todas sus propiedades de un Transfer Object ContactTO. El siguiente ejemplo muestra el codigo para el Transfer Object ContactTO que ilustra esta estrategia:


// This is the Transfer Object class inherited by
// the entity bean
public class ContactTO 
  implements java.io.Serializable { 

  // public members
  public String firstName;
  public String lastName; 
  public String address;

  // default constructor
  public ContactTO() {}

  // constructor accepting all values
  public ContactTO(String firstName, 
    String lastName, String address){
      init(firstName, lastName, address);
  }

  // constructor to create a new TO based 
  // using an existing TO instance
  public ContactTO(ContactTO contact) {
    init (contact.firstName, 
      contact.lastName, contact.address);
  }

  // method to set all the values
  public void init(String firstName, String 
              lastName, String address) { 
    this.firstName = firstName; 
    this.lastName = lastName; 
    this.address = address;
  } 

  // create a new Transfer Object 
  public ContactTO getData() { 
    return new ContactTO(this);
  } 
}

En el siguiente ejemplo podemos ver el c�digo m�s importante del bean de entidad para esta estrategia:


public class ContactEntity extends ContactTO implements 
javax.ejb.EntityBean { 
  ...
  // the client calls the getData method
  // on the ContactEntity bean instance.
  // getData() is inherited from the Transfer Object
  // and returns the ContactTO Transfer Object
  ...
}

.�Implementar la Estrategia Transfer Object Factory

El siguiente fragmento de c�digo demuestra la estrategia Transfer Object Factory. El bean de entidad extiende un Transfer Object general llamado CustomerContactTO. El CustomerContactTO implementa dos interfaces, Customer y Contact. El Transfer Object CustomerTO implementa Customer, y el Transfer Object ContactTO implementa Contact.


public interface Contact 
  extends java.io.Serializable {
  public String getFirstName();
  public String getLastName();
  public String getContactAddress();
  public void setFirstName(String firstName);
  public void setLastName(String lastName);
  public void setContactAddress(String address);
}

public class ContactTO implements Contact {
  // member attributes
  public String firstName;
  public String lastName;
  public String contactAddress;

  // implement get and set methods per the 
  // Contact interface here. 
  ...
        }
public interface Customer 
  extends java.io.Serializable {
  public String getCustomerName();
  public String getCustomerAddress();
  public void setCustomerName(String customerName);
  public void setCustomerAddress(String 
      customerAddress);
}

public class CustomerTO implements Customer {
  public String customerName;
  public String customerAddress;

  // implement get and set methods per the 
  // Customer interface here.
  ...
}

public class CustomerContactTO implements Customer, 
  Contact {
  public String firstName;
  public String lastName;
  public String contactAddress;
  public String customerName;
  public String customerAddress;

  // implement get and set methods per the 
  // Customer and Contact interfaces here.
  ...
}

En el siguiente codigo tenemos el bean de entidad para obtener estos tres Transfer Objects diferentes:


public class CustomerContactEntity extends 
  CustomerContactTO implements javax.ejb.EntityBean {

  // implement other entity bean methods...not shown

  // define constant to hold class name
  // complete Transfer Object. This is required by
  // the TransferObjectFactory.createTransferObject(...)
  public static final String COMPLETE_TO_CLASSNAME =
      "CustomerContactTO";

  // method to return CustomerContactTO Transfer Object
  public CustomerContactTO getCustomerContact() {
    return (CustomerContactTO)
      TransferObjectFactory.createTransferObject(
        this, "CustomerContactTO",
        COMPLETE_TO_CLASSNAME);
  }

// method to return CustomerTO Transfer Object
  public CustomerTO getCustomer() {
    return (CustomerTO)
      TransferObjectFactory.createTransferObject(
        this, "CustomerTO",
        COMPLETE_TO_CLASSNAME);
  }

  // method to return ContactTO Transfer Object
  public ContactTO getContact() {
    return (ContactTO)
      TransferObjectFactory.createTransferObject(
        this, "ContactTO",
        COMPLETE_TO_CLASSNAME);
  }

  // other entity bean business methods
  ...
}

Abajo tenemos el c�digo de la clase TransferObjectFactory:


import java.util.HashMap;
import java.lang.*;

/**
* The factory class that creates a Transfer Object for a
* given EJB.
*/
public class TransferObjectFactory {

/**
* Use a HashMap to cache class information for
* Transfer Object classes
*/
private static HashMap classDataInfo = new HashMap();

/**
* Create a Transfer Object for the given object. The
* given object must be an EJB Implementation and have
* a superclass that acts as the class for the entity's
* Transfer Object. Only the fields defined in this
* superclass are copied in to the Transfer Object.
*/
public static java.io.Serializable
  createTransferObject(Object ejb, 
    String whichTOType,
    String completeTOType) {
      try {
      // Get the class data for the complete 
      // Transfer Object type 
      ClassData cData = getClassData (completeTOType); 

      // Get class data for the requested TO type
      ClassData voCData = getClassData (whichTOType);

      // Create the Transfer Object of the requested 
      // Transfer Object type...
      java.lang.Object whichTO =       
          Class.forName(whichTOType).newInstance();

      // get the TO fields for the requested TO
      // from the ClassData for the requested TO
      java.lang.reflect.Field[] voFields = 
                  voCData.arrFields;

      // get all fields for the complete TO
      // from the ClassData for complete TO
      java.lang.reflect.Field[] beanFields = 
                  cData.arrFields;

      // copy the common fields from the complete TO 
      // to the fields of the requested TO
      for (int i = 0; i < voFields.length; i++) {
        try {
          String voFieldName = voFields[i].getName();
          for (int j=0; j < beanFields.length; j++) {
            // if the field names are same, copy value
            if ( voFieldName.equals( 
                  beanFields[j].getName())) {
              // Copy value from matching field
              // from the bean instance into the new
              // Transfer Object created earlier
              voFields[i].set(whichTO, 
                    beanFields[j].get(ejb));
              break;
            }
          }
        } catch (Exception e) {
          // handle exceptions that may be thrown
          // by the reflection methods...
        }
      }
    // return the requested Transfer Object
    return (java.io.Serializable)whichTO;
  } catch (Exception ex) { 
    // Handle all exceptions here...
  }
  return null;
}

/**
* Return a ClassData object that contains the 
* information needed to create
* a Transfer Object for the given class. This information
* is only obtained from the
* class using reflection once, after that it will be 
* obtained from the classDataInfo HashMap.
*/
private static ClassData getClassData(String 
  className){

  ClassData cData = 
    (ClassData)classDataInfo.get(className);

  try {
    if (cData == null) {
      // Get the class of the given object and the 
      // Transfer Object to be created
      java.lang.reflect.Field[] arrFields ;
      java.lang.Class ejbTOClass = 
          Class.forName(className);

      // Determine the fields that must be copied
      arrFields = ejbTOClass.getDeclaredFields();

      cData = new ClassData(ejbTOClass, arrFields);
      classDataInfo.put(className, cData);
    }
  } catch (Exception e) {
    // handle exceptions here...
  }
  return cData;
  }
}

/**
* Inner Class that contains class data for the
* Transfer Object classes
*/
class ClassData {
  // Transfer Object Class
  public Class    clsTransferObject;

  // Transfer Object fields
  public java.lang.reflect.Field[] arrFields;

  // Constructor
  public ClassData(Class cls, 
      java.lang.reflect.Field[] fields) {
    clsTransferObject = cls;
    arrFields = fields;
  }
}

.�Patrones Relacionados

  • Session Facade
    Session Facade, que es el interface de negocio para clientes de aplicaciones J2EE, frecuentemente utiliza Transfer Objects como mecanismo de intercambio con beans de entidad. Cuando la fachada act�a como un proxy para los servicios de negocio, el Transfer Object obtenido de los beans de entidad se puede pasar al cliente.
  • Transfer Object Assembler
    Transfer Object Assembler es un patr�n que construye Transfer Objects compuestos desde diferentes fuentes de datos. Las fuentes de datos suelen ser beans de sesi�n o de entidad a los que se podr�a solicitar que proporcionaran sus datos al Transfer Object Assembler como Transfer Objects. Estos objetos se considerar�n parte del objeto compuesto que ensambla el Transfer Object Assembler.
  • Value List Handler
    Value List Handler es otro patr�n que proporciona una lista de Transfer Objects construidos din�micamente accediendo al almacenamiento persistente en el momento de la solicitud.
  • Composite Entity
    El patr�n Transfer Object corrige la necesidad de obtener los datos de BusinessObjects a trav�s de las capas. Ciertamente este es uno de los aspectos de consideraci�n de dise�o para los beans de entidad. El patr�n Composite Entity explica los problemas implicados en el dise�o de beans de entidad gen�ricos. Este patr�n corrige los requerimientos complejos y explica los factores y consideraciones implicados en el dise�o de beans de entidad.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR