©


J2EE Pattern Catalog | Design Considerations | Refactorings | Bad Practices | Resources



Core J2EE Pattern Catalog

© CoreJ2EEPatterns
All Rights Reserved.

Last Updated:
February 3, 2003 10:57 PM

 

 

Transfer Object

Context

Application clients need to exchange data with enterprise beans.

Problem

J2EE applications implement server-side business components as session beans and entity beans. Some methods exposed by the business components return data to the client. Often, the client invokes a business object's get methods multiple times until it obtains all the attribute values.

Session beans represent the business services and are not shared between users. A session bean provides coarse-grained service methods when implemented per the Session Facade pattern.

Entity beans, on the other hand, are multiuser, transactional objects representing persistent data. An entity bean exposes the values of attributes by providing an accessor method (also referred to as a getter or get method) for each attribute it wishes to expose.

Every method call made to the business service object, be it an entity bean or a session bean, is potentially remote. Thus, in an EJB application such remote invocations use the network layer regardless of the proximity of the client to the bean, creating a network overhead. Enterprise bean method calls may permeate the network layers of the system even if the client and the EJB container holding the entity bean are both running in the same JVM, OS, or physical machine. Some vendors may implement mechanisms to reduce this overhead by using a more direct access approach and bypassing the network.

As the usage of these remote methods increases, application performance can significantly degrade. Therefore, using multiple calls to get methods that return single attribute values is inefficient for obtaining data values from an enterprise bean.

Forces

  • All access to an enterprise bean is performed via remote interfaces to the bean. Every call to an enterprise bean is potentially a remote method call with network overhead.

  • Typically, applications have a greater frequency of read transactions than update transactions. The client requires the data from the business tier for presentation, display, and other read-only types of processing. The client updates the data in the business tier much less frequently than it reads the data.
  • The client usually requires values for more than one attribute or dependent object from an enterprise bean. Thus, the client may invoke multiple remote calls to obtain the required data.
  • The number of calls made by the client to the enterprise bean impacts network performance. Chattier applications-those with increased traffic between client and server tiers-often degrade network performance.

Solution

Use a Transfer Object to encapsulate the business data. A single method call is used to send and retrieve the Transfer Object. When the client requests the enterprise bean for the business data, the enterprise bean can construct the Transfer Object, populate it with its attribute values, and pass it by value to the client.

Clients usually require more than one value from an enterprise bean. To reduce the number of remote calls and to avoid the associated overhead, it is best to use Transfer Objects to transport the data from the enterprise bean to its client.

When an enterprise bean uses a Transfer Object, the client makes a single remote method invocation to the enterprise bean to request the Transfer Object instead of numerous remote method calls to get individual attribute values. The enterprise bean then constructs a new Transfer Object instance, copies values into the object and returns it to the client. The client receives the Transfer Object and can then invoke accessor (or getter) methods on the Transfer Object to get the individual attribute values from the Transfer Object. Or, the implementation of the Transfer Object may be such that it makes all attributes public. Because the Transfer Object is passed by value to the client, all calls to the Transfer Object instance are local calls instead of remote method invocations.

Structure

Figure 8.5 shows the class diagram that represents the Transfer Object pattern in its simplest form.

Figure 8.5
Figure 8.5 Transfer Object class diagram

As shown in this class diagram, the Transfer Object is constructed on demand by the enterprise bean and returned to the remote client. However, the Transfer Object pattern can adopt various strategies, depending on requirements. The "Strategies" section explains these approaches.

Participants and Responsibilities

Figure 8.6 contains the sequence diagram that shows the interactions for the Transfer Object pattern.

Figure 8.6
Figure 8.6 Transfer Object sequence diagram

Client

This represents the client of the enterprise bean. The client can be an end-user application, as in the case of a rich client application that has been designed to directly access the enterprise beans. The client can be Business Delegates (see "Business Delegate" on page 248) or a different BusinessObject.

BusinessObject

The BusinessObject represents a role in this pattern that can be fulfilled by a session bean, an entity bean, or a Data Access Object (DAO). The BusinessObject is responsible for creating the Transfer Object and returning it to the client upon request. The BusinessObject may also receive data from the client in the form of a Transfer Object and use that data to perform an update.

TransferObject

The TransferObject is an arbitrary serializable Java object referred to as a Transfer Object. A Transfer Object class may provide a constructor that accepts all the required attributes to create the Transfer Object. The constructor may accept all entity bean attribute values that the Transfer Object is designed to hold. Typically, the members in the Transfer Object are defined as public, thus eliminating the need for get and set methods. If some protection is necessary, then the members could be defined as protected or private, and methods are provided to get the values. By offering no methods to set the values, a Transfer Object is protected from modification after its creation. If only a few members are allowed to be modified to facilitate updates, then methods to set the values can be provided. Thus, the Transfer Object creation varies depending on an application's requirements. It is a design choice as to whether the Transfer Object's attributes are private and accessed via getters and setters, or all the attributes are made public.

Strategies

The first two strategies discussed are applicable when the enterprise bean is implemented as a session bean or as an entity bean. These strategies are called Updatable Transfer Objects Strategy and Multiple Transfer Objects Strategy.

The following strategies are applicable only when the BusinessObject is implemented as an entity bean: Entity Inherits Transfer Object Strategy and Transfer Object Factory Strategy.

Updatable Transfer Objects Strategy

In this strategy, the Transfer Object not only carries the values from the BusinessObject to the client, but also can carry the changes required by the client back to the business object.

Figure 8.7 is a class diagram showing the relationship between the BusinessObject and the Transfer Object.


Figure 8.7
Figure 8.7 Updatable Transfer Object strategy - class diagram

The BusinessObject creates the Transfer Object. Recall that a client may need to access the BusinessObject values not only to read them but to modify these values. For the client to be able to modify the BusinessObject attribute values, the BusinessObject must provide mutator methods. Mutator methods are also referred to as setters or set methods.

Instead of providing fine-grained set methods for each attribute, which results in network overhead, the BusinessObject can expose a coarse-grained setData() method that accepts a Transfer Object as an argument. The Transfer Object passed to this method holds the updated values from the client. Since the Transfer Object has to be mutable, the Transfer Object class has to provide set methods for each attribute that can be modified by the client. The set methods for the Transfer Object can include field level validations and integrity checks as needed. Once the client obtains a Transfer Object from the BusinessObject, the client invokes the necessary set methods locally to change the attribute values. Such local changes do not impact the BusinessObject until the setData() method is invoked.

The setData() method serializes the client's copy of the Transfer Object and sends it to the BusinessObject. The BusinessObject receives the modified Transfer Object from the client and merges the changes into its own attributes. The merging operation may complicate the design of the BusinessObject and the Transfer Object; the "Consequences" section discusses these potential complications. One strategy to use here is to update only attributes that have changed, rather than updating all attributes. A change flag placed in the Transfer Object can be used to determine the attributes to update, rather than doing a direct comparison.

There is an impact on the design using the updatable Transfer Objects in terms of update propagation, synchronization, and version control.

Figure 8.8 shows the sequence diagram for the entire update interaction.

Figure 8.8
Figure 8.8 Updatable Transfer Object strategy - sequence diagram

Multiple Transfer Objects Strategy

Some application business objects can be very complex. In such cases, it is possible that a single business object produces different Transfer Objects, depending on the client request. There exists a one-to-many relationship between the business object and the many Transfer Objects it can produce. In these circumstances, this strategy may be considered.

For instance, when the business object is implemented as a session bean, typically applying the Session Facade pattern, the bean may interact with numerous other business components to provide the service. The session bean produces its Transfer Object from different sources. Similarly, when the BusinessObject is implemented as a coarse-grained entity bean, typically applying the Composite Entity pattern, the entity bean will have complex relationships with a number of dependent objects. In both these cases, it is good practice to provide mechanisms to produce Transfer Objects that actually represent parts of the underlying coarse-grained components.

For example, in a trading application, a Composite Entity that represents a customer portfolio can be a very coarse-grained complex component that can produce Transfer Objects that provide data for parts of the portfolio, like customer information, lists of stocks held, and so on. A similar example is a customer manager session bean that provides services by interacting with a number of other BusinessObjects and components to provide its service. The customer manager bean can produce discrete small Transfer Objects, like customer address, contact list, and so on, to represent parts of its model.

For both these scenarios, it is possible to adopt and apply the Multiple Transfer Objects Strategy so that the business component, whether a session bean or an entity bean, can create multiple types of Transfer Objects. In this strategy, the business entity provides various methods to get different Transfer Objects. Each such method creates and returns a different type of Transfer Object. The class diagram for this strategy is shown Figure 8.9.

Figure 8.9
Figure 8.9 Multiple Transfer Objects strategy class diagram

When a client needs a Transfer Object of type TransferObjectA, it invokes the entity's getDataA() method requesting TransferObjectA. When it needs a Transfer Object of type TransferObjectB, it invokes the entity's getDataB() method requesting TransferObjectB, and so on. This is shown in the sequence diagram in Figure 8.10.

Figure 8.10
Figure 8.10 Multiple Transfer Objects strategy sequence diagram

Entity Inherits Transfer Object Strategy

When the BusinessObject is implemented as an entity bean and the clients typically need to access all the data from the entity bean, then the entity bean and the Transfer Object both have the same attributes. In this case, since there exists a one-to-one relationship between the entity bean and its Transfer Object, the entity bean may be able to use inheritance to avoid code duplication.

In this strategy, the entity bean extends (or inherits from) the Transfer Object class. The only assumption is that the entity bean and the Transfer Object share the same attribute definitions. The class diagram for this strategy is shown in Figure 8.11.

Figure 8.11
Figure 8.11 Entity Inherits Transfer Object strategy class diagram

The TransferObject implements one or more getData() methods as discussed in the Multiple Transfer Objects Strategy. When the entity inherits this Transfer Object class, the client invokes an inherited getData() method on the entity bean to obtain a Transfer Object.

Thus, this strategy eliminates code duplication between the entity and the Transfer Object. It also helps manage changes to the Transfer Object requirements by isolating the change to the Transfer Object class and preventing the changes from affecting the entity bean.

This strategy has a trade-off related to inheritance. If the Transfer Object is shared through inheritance, then changes to this Transfer Object class will affect all its subclasses, potentially mandating other changes to the hierarchy.

The sequence diagram in Figure 8.12 demonstrates this strategy.

Figure 8.12
Figure 8.12 Entity Inherits Transfer Object strategy sequence diagram

The sample implementation for the Entity Inherits Transfer Object Strategy is shown in Example 8.10 (ContactTO - Transfer Object Class) and Example 8.11 (ContactEntity - Entity Bean Class).

Transfer Object Factory Strategy

The Entity Inherits Transfer Object Strategy can be further extended to support multiple Transfer Objects for an entity bean by employing a Transfer Object factory to create Transfer Objects on demand using reflection. This results in an even more dynamic strategy for Transfer Object creation.

To achieve this, define a different interface for each type of Transfer Object that must be returned. The entity bean implementation of Transfer Object superclass must implement all these interfaces. Furthermore, you must create a separate implementation class for each defined interface, as shown in the class diagram for this strategy in Figure 8.13.

Once all interfaces have been defined and implemented, create a method in the TransferObjectFactory that is passed two arguments:

  • The entity bean instance for which a Transfer Object must be created.

  • The interface that identifies the kind of Transfer Object to create.

The TransferObjectFactory can then instantiate an object of the correct class, set its values, and return the newly created Transfer Object instance.

Figure 8.13
Figure 8.13 Transfer Object Factory strategy class diagram

The sequence diagram for this strategy is shown in Figure 8.14.

Figure 8.14
Figure 8.14 Transfer Object Factory strategy sequence diagram

The client requests the Transfer Object from the BusinessEntity. The BusinessEntity passes the required Transfer Object's class to the TransferObjectFactory, which creates a new Transfer Object of that given class. The TransferObjectFactory uses reflection to dynamically obtain the class information for the Transfer Object class and construct a new Transfer Object instance. Getting values from and setting values into the BusinessEntity by the TransferObjectFactory is accomplished by using dynamic invocation.

An example implementation for this strategy is shown in the "Sample Code" section for "Implementing Transfer Object Factory Strategy" on page 284.

The benefits of applying the Transfer Object Factory Strategy are as follows:

There is less code to write in order to create Transfer Objects. The same Transfer Object factory class can be reused by different enterprise beans. When a Transfer Object class definition changes, the Transfer Object factory automatically handles this change without any additional coding effort. This increases maintainability and is less error prone to changes in Transfer Object definitions.

The Transfer Object Factory Strategy has the following consequences:

It is based on the fact that the enterprise bean implementation extends (inherits) from the complete Transfer Object. The complete Transfer Object needs to implement all the interfaces defined for different Transfer Objects that the entity bean needs to supply. Naming conventions must be adhered to in order to make this strategy work. Since reflection is used to dynamically inspect and construct Transfer Objects, there is a slight performance loss in construction. However, when the overall communication time is considered, such loss may be negligible in comparison.

There is a trade-off associated with this strategy. Its power and flexibility must be weighed against the performance overhead associated with runtime reflection.

Consequences

  • Simplifies Entity Bean and Remote Interface
    The entity bean provides a getData() method to get the Transfer Object containing the attribute values. This may eliminate having multiple get methods implemented in the bean and defined in the bean's remote interface. Similarly, if the entity bean provides a setData() method to update the entity bean attribute values in a single method call, it may eliminate having multiple set methods implemented in the bean and defined in the bean's remote interface.

  • Transfers More Data in Fewer Remote Calls
    Instead of multiple client calls over the network to the BusinessObject to get attribute values, this solution provides a single method call. At the same time, this one method call returns a greater amount of data to the client than the individual accessor methods each returned. When considering this pattern, you must consider the trade-off between fewer network calls versus transmitting more data per call. Alternatively, you can provide both individual attribute accessor methods (fine-grained get and set methods) and Transfer Object methods (coarse-grained get and set methods). The developer can choose the appropriate technique depending on the requirement.
  • Reduces Network Traffic
    A Transfer Object transfers the values from the entity bean to the client in one remote method call. The Transfer Object acts as a data carrier and reduces the number of remote network method calls required to obtain the attribute values from the entity beans. The reduced chattiness of the application results in better network performance.
  • Reduces Code Duplication
    By using the Entity Inherits Transfer Object Strategy and the Transfer Object Factory Strategy, it is possible to reduce or eliminate the duplication of code between the entity and its Transfer Object. However, with the use of Transfer Object Factory Strategy, there could be increased complexity in implementation. There is also a runtime cost associated with this strategy due to the use of dynamic reflection. In most cases, the Entity Inherits Transfer Object Strategy may be sufficient to meet the needs.
  • May Introduce Stale Transfer Objects
    Adopting the Updatable Transfer Objects Strategy allows the client to perform modifications on the local copy of the Transfer Object. Once the modifications are completed, the client can invoke the entity's setData() method and pass the modified Transfer Object to the entity. The entity receives the modifications and merges the new (modified) values with its attributes. However, there may be a problem with stale Transfer Objects. The entity updates its values, but it is unaware of other clients that may have previously requested the same Transfer Object. These clients may be holding in their local cache Transfer Object instances that no longer reflect the current copy of the entity's data. Because the entity is not aware of these clients, it is not possible to propagate the update to the stale Transfer Objects held by other clients.
  • May Increase Complexity due to Synchronization and Version Control
    The entity merges modified values into its own stored values when it receives a mutable Transfer Object from a client. However, the entity must handle the situation where two or more clients simultaneously request conflicting updates to the entity's values. Allowing such updates may result in data conflicts. Version control is one way of avoiding such conflict. As one of its attributes, the entity can include a version number or a last-modified time stamp. The version number or time stamp is copied over from the entity bean into the Transfer Object. An update transaction can resolve conflicts using the time stamp or version number attribute. If a client holding a stale Transfer Object tries to update the entity, the entity can detect the stale version number or time stamp in the Transfer Object and inform the client of this error condition. The client then has to obtain the latest Transfer Object and retry the update. In extreme cases this can result in client starvation-the client might never accomplish its updates.
  • Concurrent Access and Transactions
    When two or more clients concurrently access the BusinessObject, the container applies the transaction semantics of the EJB architecture. If, for an Enterprise bean, the transaction isolation level is set to TRANSACTION_SERIALIZED in the deployment descriptor, the container provides the maximum protection to the transaction and ensures its integrity. For example, suppose the workflow for the first transaction involves obtaining a Transfer Object, then subsequently modifying the BusinessObject attributes in the process. The second transaction, since it is isolated to serialized transactions, will obtain the Transfer Object with the correct (most recently updated) values. However, for transactions with lesser restrictions than serialized, protection is less rigid, leading to inconsistencies in the Transfer Objects obtained by competing accesses. In addition, problems related to synchronization, stale Transfer Objects, and version control will have to be dealt with.

Sample Code

Implementing the Transfer Object Pattern

Consider an example where a business object called Project is modeled and implemented as an entity bean. The Project entity bean needs to send data to its clients in a Transfer Object when the client invokes its getProjectData() method. The Transfer Object class for this example, ProjectTO, is shown in Example 8.3.

Example 8.3 Implementing the Transfer Object Pattern - Transfer Object Class

// 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...
}

The sample code for the entity bean that uses this Transfer Object is shown in Example 8.4.

Example 8.4 Implementing the Transfer Object Pattern - Entity Bean Class

...
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;
    }
    ...
}

Implementing the Updatable Transfer Objects Strategy

Example 8.4 can be extended to implement Updatable Transfer Objects Strategy. In this case, the entity bean would provide a setProjectData() method to update the entity bean by passing a Transfer Object that contains the data to be used to perform the update. The sample code for this strategy is shown in Example 8.5.

Example 8.5 Implementing Updatable Transfer Objects Strategy

...
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;
  }
  ...
}

Implementing the Multiple Transfer Objects Strategy

Consider an example where a Resource entity bean is accessed by clients to request different Transfer Objects. The first type of Transfer Object, ResourceTO, is used to transfer data for a small set of attributes. The second type of Transfer Object, ResourceDetailsTO, is used to transfer data for a larger set of attributes. The client can use the former Transfer Object if it needs only the most basic data represented by that Transfer Object, and can use the latter if it needs more detailed information. Note that this strategy can be applied in producing two or more Transfer Objects that contain different data, and not just subset-superset as shown here.

The sample code for the two Transfer Objects for this example are shown in Example 8.6 and Example 8.7. The sample code for the entity bean that produces these Transfer Objects is shown in Example 8.8, and finally the entity bean client is shown in Example 8.9.

Example 8.6 Multiple Transfer Objects Strategy - 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;
  ...
}


Example 8.7 Multiple Transfer Objects Strategy - 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;
}


Example 8.8 Multiple Transfer Objects Strategy - Resource Entity Bean

// 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
  ...
}


Example 8.9 Multiple Transfer Objects Strategy - Entity Bean Client

...
  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();
  ...

Implementing the Entity Inherits Transfer Object Strategy

Consider an example where an entity bean ContactEntity inherits all its properties from a Transfer Object ContactTO. Example 8.10 shows the code sample for an example Transfer Object ContactTO that illustrates this strategy.

Example 8.10 Entity Inherits Transfer Object Strategy - Transfer Object Class

// 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);
  } 
}

The entity bean sample code relevant to this pattern strategy is shown in Example 8.11.

Example 8.11 Entity Inherits Transfer Object Strategy - Entity Bean Class

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
  ...
}

Implementing Transfer Object Factory Strategy

Example 8.12 demonstrates the Transfer Object Factory strategy. The entity bean extends a complete Transfer Object called CustomerContactTO. The CustomerContactTO Transfer Object implements two interfaces, Customer and Contact. The CustomerTO Transfer Object implements Customer, and the ContactTO Transfer Object implements Contact.

Example 8.12 Transfer Object Factory Strategy - Transfer Objects and Interfaces

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.
  ...
}

The entity bean code sample to obtain these three different Transfer Objects is shown Example 8.13.

Example 8.13 Transfer Object Factory Strategy - Entity Bean Class

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
  ...
}

The TransferObjectFactory class is shown in Example 8.14.

Example 8.14 Transfer Object Factory Strategy - Factory Class

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;
  }
}

Related Patterns

  • Session Facade
    The Session Facade, which is the business interface for clients of J2EE applications, frequently uses Transfer Objects as an exchange mechanism with participating entity beans. When the facade acts as a proxy to the underlying business service, the Transfer Object obtained from the entity beans can be passed to the client.

  • Transfer Object Assembler
    The Transfer Object Assembler is a pattern that builds composite Transfer Objects from different data sources. The data sources are usually session beans or entity beans that may be requested to provide their data to the Transfer Object Assembler as Transfer Objects. These Transfer Objects are considered to be parts of the composite object that the Transfer Object Assembler assembles.
  • Value List Handler
    The Value List Handler is another pattern that provides lists of Transfer Objects constructed dynamically by accessing the persistent store at request time.
  • Composite Entity
    The Transfer Object pattern addresses the need of getting data from BusinessObjects across tiers. This certainly is one aspect of design considerations for entity beans. The Composite Entity pattern discusses issues involved in designing coarse-grained entity beans. The Composite Entity pattern addresses complex requirements and discusses other factors and considerations involved in entity bean design.

 

  © 2001, Core J2EE Patterns, All Rights Reserved.