Context
Application clients need to exchange data with enterprise beans.
Problem
Java 2 Platform, Enterprise
Edition (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 Enterprise JavaBeans
(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
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 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 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 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 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 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 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 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 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 TransferObjectFactory can then instantiate an object of the correct
class, set its values, and return the newly created Transfer Object instance.
Figure 8.13 Transfer Object Factory strategy class diagram
The sequence diagram for this strategy is shown in 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.
Contact Us© 2001-2002 Sun Microsystems,
Inc. All Rights Reserved.
|