Context
In a Java 2 Platform, Enterprise
Edition (J2EE) application, the server-side business components are implemented
using session beans, entity beans, DAOs, and so forth. Application clients
frequently need to access data that is composed from multiple objects.
Problem
Application clients typically require the data for the model or parts
of the model to present to the user or to use for an intermediate processing
step before providing some service. The application model is an abstraction
of the business data and business logic implemented on the server side
as business components. A model may be expressed as a collection of objects
put together in a structured manner (tree or graph). In a J2EE application,
the model is a distributed collection of objects such as session beans,
entity beans, or DAOs and other objects. For a client to obtain the data
for the model, such as to display to the user or to perform some processing,
it must access individually each distributed object that defines the model.
This approach has several drawbacks:
-
Because the client must access each distributed
component individually, there is a tight coupling between the client
and the distributed components of the model over the network
-
The client accesses the distributed components
via the network layer, and this can lead to performance degradation
if the model is complex with numerous distributed components. Network
and client performance degradation occur when a number of distributed
business components implement the application model and the client
directly interacts with these components to obtain model data from
that component. Each such access results in a remote method call that
introduces network overhead and increases the chattiness between the
client and the business tier.
-
The client must reconstruct the model
after obtaining the model's parts from the distributed components.
The client therefore needs to have the necessary business logic to
construct the model. If the model construction is complex and numerous
objects are involved in its definition, then there may be an additional
performance overhead on the client due to the construction process.
In addition, the client must contain the business logic to manage
the relationships between the components, which results in a more
complex, larger client. When the client constructs the application
model, the construction happens on the client side. Complex model
construction can result in a significant performance overhead on the
client side for clients with limited resources.
-
Because the client is tightly coupled to the model, changes to the
model require changes to the client. Furthermore, if there are different
types of clients, it is more difficult to manage the changes across
all client types. When there is tight coupling between the client
and model implementation, which occurs when the client has direct
knowledge of the model and manages the business component relationships,
then changes to the model necessitate changes to the client. There
is the further problem of code duplication for model access, which
occurs when an application has many types of clients. This duplication
makes client (code) management difficult when the model changes.
Forces
-
Separation of business logic is required
between the client and the server-side components.
-
Because the model consists of distributed
components, access to each component is associated with a network
overhead. It is desirable to minimize the number of remote method
calls over the network.
-
The client typically needs only to obtain
the model to present it to the user. If the client must interact with
multiple components to construct the model on the fly, the chattiness
between the client and the application increases. Such chattiness
may reduce the network performance.
-
Even if the client wants to perform an
update, it usually updates only certain parts of the model and not
the entire model.
-
Clients do not need to be aware of the
intricacies and dependencies in the model implementation. It is desirable
to have loose coupling between the clients and the business components
that implement the application model.
-
Clients do not otherwise need to have the additional business logic
required to construct the model from various business components.
Solution
Use a Transfer Object Assembler to build the required model or
submodel. The Transfer Object Assembler uses Transfer Objects to retrieve
data from various business objects and other objects that define the model
or part of the model.
The Transfer Object Assember constructs a composite Transfer Object that
represents data from different business components. The Transfer Object
caries the data for the model to the client in a single method call. Since
the model data can be complex, it is recommended that this Transfer Object
be immutable. That is, the client obtains such Transfer Objects with the
sole purpose of using them for presentation and processing in a read-only
manner. Clients are not allowed to make changes to the Transfer Objects.
When the client needs the model data, and if the model is represented
by a single coarse-grained component (such as a Composite Entity), then
the process of obtaining the model data is simple. The client simply requests
the coarse-grained component for its composite Transfer Object. However,
most real-world applications have a model composed of a combination of
many coarse-grained and fine-grained components. In this case, the client
must interact with numerous such business components to obtain all the
data necessary to represent the model. The immediate drawbacks of this
approach can be seen in that the clients become tightly coupled to the
model implementation (model elements) and that the clients tend to make
numerous remote method invocations to obtain the data from each individual
component.
In some cases, a single coarse-grained component provides the model or
parts of the model as a single Transfer Object (simple or composite).
However, when multiple components represent the model, a single Transfer
Object (simple or composite) may not represent the entire model. To represent
the model, it is necessary to obtain Transfer Objects from various components
and assemble them into a new composite Transfer Object. The server, not
the client, should perform such "on-the-fly" construction of
the model.
Structure
Figure 8.27 shows the class diagram representing the relationships for
the Transfer Object Assembler pattern.
Figure 8.27 Transfer Object Assembler class diagram
Participants and Responsibilities
The sequence diagram in Figure 8.28 shows the interaction between the
various participants in the Transfer Object Assembler pattern.
Figure 8.28 Transfer Object Assembler sequence diagram
TransferObjectAssembler
The TransferObjectAssembler is the main class of this pattern. The TransferObjectAssembler
constructs a new Transfer Object based on the requirements of the application
when the client requests a composite Transfer Object. The TransferObjectAssembler
then locates the required BusinessObject instances to retrieve data to
build the composite Transfer Object. BusinessObjects are business-tier
components such as entity beans and session beans, DAOs, and so forth.
Client
If the TransferObjectAssembler is implemented as an arbitrary Java object,
then the client is typically a Session Facade that provides the controller
layer to the business tier. If the TransferObjectAssembler is implemented
as a session bean, then the client can be a Session Facade or a Business
Delegate.
BusinessObject
The BusinessObject participates in the construction of the new Transfer
Object by providing the required data to the TransferObjectAssembler.
Therefore, the BusinessObject is a role that can be fulfilled by a session
bean, an entity bean, a DAO, or a regular Java object.
TransferObject
The TransferObject is a composite Transfer Object that is constructed
by the TransferObjectAssembler and returned to the client. This represents
the complex data from various components that define the application model.
BusinessObject
BusinessObject is a role that can be fulfilled by a session bean, entity
bean, or DAO. When the assembler needs to obtain data directly from the
persistent storage to build the Transfer Object, it can use a DAO. This
is shown as the DataAccessObject object in the diagrams.
Strategies
This section explains different strategies for implementing a Transfer
Object Assembler pattern.
Java Object Strategy
The TransferObjectAssembler can be an arbitrary Java object and need
not be an enterprise bean. In such implementations, a session bean usually
fronts the TransferObjectAssembler. This session bean is typically a Session
Facade that performs its other duties related to providing business services.
The TransferObjectAssembler runs in the business tier, regardless of the
implementation strategies. The motivation for this is to prevent the remote
invocations from the TransferObjectAssembler to the source objects from
crossing the tier.
Session Bean Strategy
This strategy implements the TransferObjectAssembler as a session bean
(as shown in the class diagram). If a session bean implementation is preferred
to provide the TransferObjectAssembler as a business service, it is typically
implemented as a stateless session bean. The business components that
make up the application model are constantly involved in transactions
with various clients. As a result, when a TransferObjectAssembler constructs
a new composite Transfer Object from various business components, it produces
a snapshot of the model at the time of construction. The model could change
immediately thereafter if another client changes one or more business
components, effectively changing the business application model.
Therefore, implementing TransferObjectAssembler as a stateful session
bean provides no benefits over implementing it as a stateless session
bean, as preserving the state of the composite model data value when the
underlying model is changing is futile. If the underlying model changes,
it causes the Transfer Object held by the assembler to become stale. The
TransferObjectAssembler, when next asked for the Transfer Object, either
returns a stale state or reconstructs the Transfer Object to obtain the
most recent snapshot. Therefore, it is recommended that the assembler
be a stateless session bean to leverage the benefits of stateless over
stateful session beans.
However, if the underlying model rarely changes, then the assembler may
be a stateful session bean and retain the newly constructed Transfer Object.
In this case, the TransferObjectAssembler must include mechanisms to recognize
changes to the underlying model and to reconstruct the model for the next
client request.
Business Object Strategy
The BusinessObject role in this pattern can be supported by different
types of objects, as explained below.
-
The BusinessObject can be a session bean.
The Transfer Object Assembler may use a Service Locator (see "Service
Locator" on page 368) to locate the required session bean. The
Transfer Object Assembler requests this session bean to provide the
data to construct the composite Transfer Object.
-
The BusinessObject can be an entity bean.
The Transfer Object Assembler may use a Service Locator to locate
the required entity bean. The Transfer Object Assembler requests this
entity bean to provide the data to construct the composite Transfer
Object.
-
The BusinessObject can be a DAO. The Transfer
Object Assembler requests this DAO to provide the data to construct
the composite Transfer Object.
-
The BusinessObject can be an arbitrary
Java object. The Transfer Object Assembler requests this Java object
to provide the data to construct the composite Transfer Object.
-
The BusinessObject can be another Transfer Object Assembler. The
first Transfer Object Assembler requests the second Transfer Object
Assembler to provide the data to construct the composite Transfer
Object.
Consequences
-
Separates Business Logic
When the client includes logic to manage the interactions with distributed
components, it becomes difficult to clearly separate business logic
from the client tier. The Transfer Object Assembler contains the business
logic to maintain the object relationships and to construct the composite
Transfer Object representing the model. The client needs no knowledge
of how to construct the model or the different components that provide
data to assemble the model.
-
Reduces Coupling Between Clients
and the Application Model
The Transfer Object Assembler hides the complexity of the construction
of model data from the clients and establishes a loose coupling between
clients and the model. With loose coupling, if the model changes,
then the Transfer Object Assembler requires a corresponding change.
However, the client is not dependent on the model construction and
interrelationships between model business components, so model changes
do not directly affect the client. In general, loose coupling is preferred
to tight coupling.
-
Improves Network Performance
The Transfer Object Assembler drastically reduces the network overhead
of remote method calls and chattiness. The client can request the
data for the application model from the Transfer Object Assembler
in a single remote method call. The assembler constructs and returns
the composite Transfer Object for the model. However, the composite
Transfer Object may contain a large amount of data. Thus, while use
of the Transfer Object Assembler reduces the number of network calls,
there is an increase in the amount of data transported in a single
call. This trade-off should be considered in applying this pattern.
-
Improves Client Performance
The server-side Transfer Object Assembler constructs the model as
a composite Transfer Object without using any client resources. The
client spends no time assembling the model.
-
Improves Transaction Performance
Typically, updates are isolated to a very small part of the model
and can be performed by fine-grained transactions. These transactions
focus on isolated parts of the model instead of locking up the coarse-grained
object (model). After the client obtains the model and displays or
processes it locally, the user (or the client) may need to update
or otherwise modify the model. The client can interact directly with
a Session Facade to accomplish this at a suitable granularity level.
The Transfer Object Assembler is not involved in the transaction to
update or modify the model. There is better performance control because
transactional work with the model happens at the appropriate level
of granularity.
-
May Introduce Stale Transfer Objects
The Transfer Object Assembler constructs Transfer Objects on demand.
These Transfer Objects are snapshots of the current state of the model,
represented by various business components. Once the client obtains
a Transfer Object from the assembler, that Transfer Object is entirely
local to the client. Since the Transfer Objects are not network-aware,
other changes made to the business components used to construct the
Transfer Object are not reflected in the Transfer Objects. Therefore,
after the Transfer Object is obtained, it can quickly become stale
if there are transactions on the business components.
Sample Code
Implementing the Transfer Object Assembler
Consider a Project Management application where a number of business-tier
components define the complex model. Suppose a client wants to obtain
the model data composed of data from various business objects, such as:
-
Project Information from the Project component
-
Project Manager information from the ProjectManager
component
-
List of Project Tasks from the Project
component
-
Resource Information from the Resource component
A composite Transfer Object to contain this data can be defined as shown
in Example 8.24. A Transfer Object Assembler pattern can be implemented
to assemble this composite Transfer Object. The Transfer Object Assembler
sample code is listed in Example 8.28.
Example 8.24 Composite Transfer Object Class
public class ProjectDetailsData {
public ProjectTO projectData;
public ProjectManagerTO projectManagerData;
public Collection listOfTasks;
...
} |
The list of tasks in the ProjectDetailsData is a collection of TaskResourceTO
objects. The TaskResourceTO is a combination of TaskTO and ResourceTO.
These classes are shown in Example 8.25, Example 8.26, and Example 8.27.
Example 8.25 TaskResourceTO Class
public class TaskResourceTO {
public String projectId;
public String taskId;
public String name;
public String description;
public Date startDate;
public Date endDate;
public ResourceTO assignedResource;
...
public TaskResourceTO(String projectId,
String taskId, String name, String description,
Date startDate, Date endDate, ResourceTO
assignedResource) {
this.projectId = projectId;
this.taskId = taskId;
...
this.assignedResource = assignedResource;
}
...
} |
Example 8.26 TaskTO Class
public class TaskTO {
public String projectId;
public String taskId;
public String name;
public String description;
public Date startDate;
public Date endDate;
public assignedResourceId;
public TaskTO(String projectId, String taskId,
String name, String description, Date startDate,
Date endDate, String assignedResourceId) {
this.projectId = projectId;
this.taskId = taskId;
...
this.assignedResource = assignedResource;
}
...
} |
Example 8.27 ResourceTO Class
public class ResourceTO {
public String resourceId;
public String resourceName;
public String resourceEmail;
...
public ResourceTO (String resourceId, String
resourceName, String resourceEmail, ...) {
this.resourceId = resourceId;
this.resourceName = resourceName;
this.resourceEmail = resourceEmail;
...
}
} |
The ProjectDetailsAssembler class that assembles the ProjectDetailsData
object is listed in Example 8.28.
Example 8.28 Implementing the Transfer Object Assembler
public class ProjectDetailsAssembler
implements javax.ejb.SessionBean {
...
public ProjectDetailsData getData(String projectId){
// Construct the composite Transfer Object
ProjectDetailsData pData = new
ProjectDetailsData();
//get the project details;
ProjectHome projectHome =
ServiceLocator.getInstance().getHome(
"Project", ProjectEntityHome.class);
ProjectEntity project =
projectHome.findByPrimaryKey(projectId);
ProjectTO projTO = project.getData();
// Add Project Info to ProjectDetailsData
pData.projectData = projTO;
//get the project manager details;
ProjectManagerHome projectManagerHome =
ServiceLocator.getInstance().getHome(
"ProjectManager", ProjectEntityHome.class);
ProjectManagerEntity projectManager =
projectManagerHome.findByPrimaryKey(
projTO.managerId);
ProjectManagerTO projMgrTO =
projectManager.getData();
// Add ProjectManager info to ProjectDetailsData
pData.projectManagerData = projMgrTO;
// Get list of TaskTOs from the Project
Collection projTaskList = project.getTasksList();
// construct a list of TaskResourceTOs
ArrayList listOfTasks = new ArrayList();
Iterator taskIter = projTaskList.iterator();
while (taskIter.hasNext()) {
TaskTO task = (TaskTO) taskIter.next();
//get the Resource details;
ResourceHome resourceHome =
ServiceLocator.getInstance().getHome(
"Resource", ResourceEntityHome.class);
ResourceEntity resource =
resourceHome.findByPrimaryKey(
task.assignedResourceId);
ResourceTO resTO = resource.getResourceData();
// construct a new TaskResourceTO using Task
// and Resource data
TaskResourceTO trTO = new TaskResourceTO(
task.projectId, task.taskId,
task.name, task.description,
task.startDate, task.endDate,
resTO);
// add TaskResourceTO to the list
listOfTasks.add(trTO);
}
// add list of tasks to ProjectDetailsData
pData.listOfTasks = listOfTasks;
// add any other data to the Transfer Object
...
// return the composite Transfer Object
return pData;
}
...
} |
Related Patterns
-
Transfer Object
The Transfer Object Assembler uses the Transfer Object pattern in
order to create and transport Transfer Objects to the client. The
Transfer Objects created carry the data representing the application
model from the business tier to the clients requesting the data.
-
Composite Entity
The Composite Entity pattern promotes a coarse-grained entity bean
design, where entities can produce composite Transfer Objects similar
to the one produced by the Transfer Object Assembler. However, the
Transfer Object Assembler is more applicable when the composite Transfer
Object constructed is derived from a number of components (session
beans, entity beans, DAOs, and so forth), whereas the Composite Entity
pattern constructs the Transfer Object from its own data (that is,
a single entity bean).
-
Session Facade
The Transfer Object Assembler is typically implemented as a stateless
session bean. As such, it could be viewed as a limited special application
of the Session Facade pattern. More importantly, Transfer Object Assembler
constructs composite Transfer Objects that are immutable. Therefore,
the client receiving this composite Transfer Object can only use the
data for its presentation and processing purposes. The client cannot
update the Transfer Object. If the client needs to update the business
objects that derive the composite Transfer Object, it may have to
access the Session Facade (session bean) that provides that business
service.
-
Data Access Object
A possible strategy for the Transfer Object Assembler involves obtaining
data for the composite Transfer Object from the persistent store without
enterprise bean involvement. The Data Access Object pattern can be
applied, thus leveraging its benefits to provide persistent storage
access to the Transfer Object Assembler.
-
Service Locator
The Transfer Object Assembler needs to locate and use various business
objects. The Service Locator pattern can be used in conjunction with
the Transfer Object Assembler pattern whenever a business object or
a service needs to be located.
Contact Us© 2001-2002 Sun Microsystems,
Inc. All Rights Reserved.
|