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