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.
As well as being a highly configurable way to instantiate objects, a Spring bean factory can be configured to return a proxy instead of the original object. A proxy, which is also known as an interceptor, is an object that masquerades as the original object. It executes arbitrary code before and after invoking the original object. In an enterprise Java application, interceptors
can be used for a number of purposes, including security, database connection management, and transaction management.
In this example application, we can configure the Spring bean factory to wrap TransferFacade with a proxy that manages transactions. To do that, we must define several beans, including those shown in figure 2. This diagram shows the TransferFacade bean, along with PlatformTransactionManager, TransactionInterceptor, and BeanNameAutoProxyCreator, the Spring classes that make TransferFacade transactional.
Figure 2 The Spring bean definitions required to make TransferFacade transactional
The BeanNameAutoProxyCreator bean wraps TransferFacade with a TransactionInterceptor, which manages transactions using the PlatformTransactionManager. The PlatformTransactionManager in this example is implemented by the HibernateTransactionManager class, which uses the Hibernate Transaction interface to begin, commit, and roll back transactions. Listing 1 shows an excerpt from the XML configuration file that defines these beans.
Listing 1 Configuring Spring transaction management
Let’s take a closer look at this listing. The following numbered list refers to the bullet points in Listing 1.
- This defines a bean called TransferFacade, which is implemented by the TransferFacadeImpl class.
- This defines a bean called PlatformTransactionManager, which is implemented by the HibernateTransactionManager class that manages transactions using the Hibernate API.
- This defines a bean called TransactionInterceptor, which is implemented by the TransactionInterceptor class that makes an object transactional. TransactionInterceptor intercepts calls to the object and calls a PlatformTransactionManager to begin, commit, and roll back transactions. It has a transactionManager property, which specifies which PlatformTransactionManager to use, and a transactionAttributeSource property, which specifies which methods to make transactional. In this example, all method calls are configured to be transactional.
- This defines a bean called BeanNameAutoProxyCreator, which wraps TransferFacade with TransactionInterceptor. It has an interceptorNames property, which specifies the list of interceptors to apply, and a beanNames property, which specifies the beans to wrap with interceptors.
These bean definitions arrange for the bean factory to wrap TransferFacade with TransactionInterceptor. When the presentation tier invokes what it thinks is TransferFacade, TransactionInterceptor is invoked instead. The sequence of events is shown in figure 3.
Figure 3 Using Spring interceptors to manage transactions
Let’s look at the sequence of events:
- The presentation tier calls TransferFacade but the call is routed to TransactionInterceptor.
- TransactionInterceptor begins a transaction by calling PlatformTransactionManager, which begins a transaction using either the JTA provided by the application server or the transaction management API provided by the persistence framework.
- TransactionInterceptor invokes the real TransferFacadeImpl.
- The call to TransferFacadeImpl returns.
- TransactionInterceptor commits the transaction by calling PlatformTransactionManager.
- The call to TransactionInterceptor returns.
In step 5 TransactionInterceptor could also roll back the transaction if the TransferMoney service threw an exception. By default, TransactionInterceptor emulates EJBs and rolls back a transaction if a RuntimeException is thrown. However, you can write rollback rules that specify which exceptions should cause a transaction to be rolled back. Using rollback rules simplifies the application and decouples it from the transaction management APIs by eliminating code that programmatically rolls back transactions. This is one example of how the Spring framework is more flexible than an EJB container.
Another benefit of using Spring is that you can test your transactional POJOs without deploying them in the application server. Because code that uses JDO or Hibernate can also be tested within your IDE, you can often do a lot of development without ever starting up an application server. In fact, I often find that the only time I need to use one is when developing code that uses a service such as JMS that is provided by the application server. Even when working on the presentation tier I’m able to use a simpler web container such as Jetty. This is yet another example of how lightweight frameworks make your life as a developer easier.
The role of AOP in the Spring framework
The technology underlying Spring’s transaction management mechanism is known as Aspect-Oriented Programming (AOP). AOP is a declarative mechanism for changing the behavior of an application without requiring any modification to the application itself. You write rules that specify new code to be executed when methods are called and, in some cases, fields are accessed or objects instantiated. In this example the BeanNameAutoProxyCreator arranged for the TransactionInterceptor to be executed whenever the TransferFacade was called without any code changes. AOP is not limited to transaction management, and in this book you will see examples of interceptors that implement security, manage database connections, and automatically retry transactions.
I’m using the Spring AOP implementation in this book for the simple reason that it provides the AOP interceptors for managing transactions, JDO, and Hibernate connections. It is important to remember that the techniques described in this book will work equally as well with other lightweight containers such as PicoContainer [PicoContainer], and other AOP mechanisms like AspectJ [Laddad 2003]. However, as of this writing, Spring provides the best implementation of the features required by enterprise applications such as the Food to Go application, which is the example application used throughout the rest of this book.
The Spring framework is one example of a growing number of technologies that are compelling alternatives to EJBs. Using Spring AOP provides the same benefits of using EJB session beans but also allows you to use POJOs for your problem domain. An EJB container provides a large number of services, including transaction management. But is it worth compromising the design of the application to take advantage of these services—especially if you can implement them using a technology such as Spring in an à la carte fashion?
Editor’s Note: To complete this series go to www.developer.com/java/ejb/article.php/3594121
About the Author
Chris Richardson is a developer and architect with over 20 years of experience. His consulting company specializes in jumpstarting projects and mentoring teams. Chris has been a technical leader at Insignia, BEA, and elsewhere. He has a computer science degree from the University of Cambridge in England and lives in Oakland, CA.
About the Book
POJOs in Action
By Chris Richardson