![]() |
|
|
![]()
|
Transfer Object AssemblerContextIn a 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. ProblemApplication 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:
Forces
SolutionUse 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. StructureFigure 8.27 shows the class diagram representing the relationships for the Transfer Object Assembler pattern.
Participants and ResponsibilitiesThe sequence diagram in Figure 8.28 shows the interaction between the various participants in the Transfer Object Assembler pattern.
TransferObjectAssemblerThe 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. ClientIf 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. BusinessObjectThe 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. TransferObjectThe 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. BusinessObjectBusinessObject 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. StrategiesThis section explains different strategies for implementing a Transfer Object Assembler pattern. Java Object StrategyThe 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 StrategyThis 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 StrategyThe BusinessObject role in this pattern can be supported by different types of objects, as explained below.
Consequences
Sample CodeImplementing the Transfer Object AssemblerConsider 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:
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; } ... } 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; } ... } 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
|
|||||||||||||||||||||||
© 2001, Core J2EE Patterns, All Rights Reserved. |