This is part two of a three part series on Developing in POJOs. See Part 1 for material on
- Comparing classic EJB to POJO approaches
- Using an object-oriented design
- Benefits of using POJOs
- Transparent persistence with JDO and Hibernate
- Encapsulating the calls to the persistence framework
Another way to improve a J2EE application is to eliminate the DTOs, also known as value objects. A DTO is a simple object consisting of only fields (i.e., no behavior) and is used to return data from the business tier to the presentation tier. An EJB application uses DTOs because EJB 2 entity beans cannot be efficiently accessed by the presentation tier. Each call to an entity bean might be a remote call and/or a separate database transaction. As a result, they must only be accessed by the session façade, which copies data from them into DTOs. The trouble with using DTOs, however, is that they and the code that creates them are extremely tedious to develop and can sometimes be a significant portion of a J2EE application. Hibernate, JDO, and EJB 3 objects do not have this limitation and can be accessed directly by the presentation tier. As a result, we eliminate many or all of the DTOs in an application.
Returning domain objects to the presentation tier
There are a couple of ways to return Hibernate, JDO, and EJB 3 objects to the presentation tier. One option is for the business tier to return objects that are still persistent. This can be simpler to implement but requires the presentation tier to manage database connections, which is sometimes neither desirable nor possible.
Another approach is for the business tier to return detached objects. A detached object is a previously persistent object that is no longer connected to the database. Instead of copying values from a persistent object into a DTO, the business tier detaches the object and returns it to the persistent tier. This approach eliminates the need for DTOs while keeping all database accesses in the business tier.
Different persistence frameworks handle detached objects in different ways. In Hibernate and EJB 3, objects are automatically detached but the application must ensure that all of the objects required by the presentation tier are loaded, which can sometimes require extra calls to the persistence framework. In JDO 2.0 an application must explicitly detach the required objects by calling a JDO API.
Using a façade to retrieve and detach domain objects
An important design decision is determining which class will be responsible for calling the persistence framework to retrieve and detach the objects required by the presentation tier. For example, the money transfer business logic must retrieve the recent transactions and detach them along with the account objects. You could make this the responsibility of the TransferService, but doing so would make it more complicated and couple it to the needs of the presentation tier. Moreover, because the business tier must sometimes call the persistent framework to ensure that the domain objects can be returned to the presentation tier, making the TransferService call the detachment logic would mix together pure business logic with infrastructure details.
Unless the service is very simple and contains little or no business logic, a better option is to retrieve and detach the required objects in a separate class—TransferFacadeImpl. As figure 1 shows, TransferFacadeImpl implements the TransferFacade interface, which specifies the methods that can be called by the business logic's client and plays a role similar to that of an EJB component interface. It returns a TransferResult that contains the domain objects.
Figure 1 The design of TransferFacade, which encapsulates the business logic and detaches objects
Like the EJB we saw earlier, TransferFacade defines a transfer() method that returns a TransferResult. It calls TransferService and TransactionRepository, and creates TransferResult. As you can see, TransferResult is the only DTO in this example. The rest of the objects returned to the presentation tier are domain objects.
Making POJOs transactional
Let's review what we have done so far. We replaced a procedural design with an object-oriented design, replaced entity beans with POJOs plus a persistence framework (either Hibernate or JDO), and eliminated DTOs. Because of these changes, we have a design that is easier to understand, maintain, and extend. In addition, the edit-compile-debug cycle is extremely short. We now have an application where most of the code is sufficiently modular that you can write unit tests. We haven't yet discussed how to eliminate the TransferService EJB. Even though it is a simple class that calls the object model classes, development slows down considerably any time we have to change it because of the deployment requirement. Let's see what we can do about that.
Although session beans support distributed applications, the main reason they are used in many applications is because they provide container-managed transactions. The EJB container automatically starts a transaction when a business method is invoked and commits the transaction when the method returns. It rolls back the transaction if a RuntimeException is thrown. Container-managed transactions are extremely useful. They free you from writing error-prone code to manually manage transactions. Consequently, if you want to replace session beans with POJOs, you should use an equally convenient mechanism to manage transactions. This naturally takes us to the Spring framework.
Managing transactions with Spring
There are several lightweight mechanisms for making POJOs transactional. One very popular framework that provides this capability is Spring. Spring is a powerful J2EE application framework that makes it significantly easier to develop enterprise Java applications. It provides a large number of features, and I'm only going to provide a brief overview of a few of them in this article. For more information see Spring in Action [Walls 2005].
The Spring framework provides an extremely easy-to-use mechanism for making POJOs transactional that works in a similar way to container-managed transactions. Spring will automatically begin a transaction when a POJO method is invoked and commit the transaction when the method returns. It can also roll back a transaction if an error occurs. Spring can manage transactions using the application server's implementation of the Java Transaction API (JTA) if the application accesses multiple resources such as a database and JMS. Alternatively, Spring can manage transactions using the persistence framework or JDBC transaction management APIs, which are simpler and easier to use because they do not require an application server.
When using the Spring framework, we can make a POJO transactional by defining it as a Spring bean, which is simply an object that is instantiated and managed by Spring. Defining a Spring bean requires only a few lines of XML. The XML is similar to a deployment descriptor and configures Spring's lightweight container, which is a sophisticated factory for constructing objects. Each entry in the XML file defines the configuration of a Spring bean, which includes its name, its POJO implementation class, and a description of how to instantiate and initialize it. An application obtains a bean by calling the Spring bean factory with the name and expected type of the bean:
BeanFactory beanFactory = ... TransferFacade tf = (TransferFacade) beanFactory.getBean("TransferFacade", TransferFacade.class);
This code fragment calls the BeanFactory.getBean() method with TransferFacade as the name of the bean and TransferFacade as the expected class. The bean factory will throw an exception if a bean with that name does not exist or is of a different type.