devxlogo

The Java EE Application as an EJB/Spring/Hibernate Hybrid

The Java EE Application as an EJB/Spring/Hibernate Hybrid

lain old Java object (POJO)-based architectures and lighter-weight development models using tools such as Spring and Hibernate have gained considerable acceptance in the enterprise Java space during the past few years. Meanwhile, specification-supported component architectures that use standards such as Enterprise Java Beans (EJBs) have lost ground. However, the new Java Platform, Enterprise Edition 5 (Java EE 5) specification has introduced significant changes to the component architecture, primarily addressing the drawbacks that prevented more widespread acceptance of previous versions.

Incorporating feedback from the industry and users, Java EE 5 lays out a new lightweight POJO-based architecture built on the concepts of Inversion of Control (IoC) for dependency management and object relation mapping (ORM) for persistence. Previous EJB versions were relatively cumbersome to build and support, but the latest EJB 3.0 specification featured in Java EE 5 can be implemented easily with very little code intrusion. (Read the previous DevX articles “Getting Started with EJB 3.0 and Enterprise Bean Components“, “Banish Your Resistance to Persistence with the EJB 3.0 Persistence API“, and “A Test-Driven Exploration of the Advanced Features of EJB 3.0” to learn about EJB 3.0.)

Java EE 5 provides all the features and functions necessary to build a robust enterprise application right in the EJB 3.0 container, but you still can use the power, flexibility, and relative strengths of Spring and Hibernate to further improve the productivity and quality of your applications. This article demonstrates how to build a Java EE application that uses EJB 3.0, Spring 2.0, and Hibernate together. By implementing a component architecture, the application employs EJB 3.0 while using Spring 2.0 as a dependency-injection, AOP container and Hibernate as an ORM persistence provider.

The goal is not only to introduce the idea of using these popular technologies as complements to the new EJB 3.0 model, but also to provide a development model for teams who already have made significant investments in using these technologies. The article doesn’t recommend one architecture over another, but merely proposes an option for you to add to your toolbox. You can also choose pieces of the proposed solution to incorporate in your application architecture.

What You Need
Glassfish Application Server V2 or
any Java EE 5-compliant application server
Spring 2.0
Hibernate 3.1
Eclipse Java IDE

Leveraging Spring with EJB 3.0
EJB 3.0 caters to the growing preference among enterprise Java developers for a POJO-based development model and IoC support in the container. However, this does not mean that tools like Spring don’t have a place, or that EJB 3.0 and Spring have to be an either/or proposition. They certainly can be complementary. In fact, you can continue using the same development pattern you do with Spring and seamlessly integrate it with EJB 3.0 components—all while filling in some holes in the EJB 3.0 specification.

The composite model proposed in this article enables you to combine EJB 3.0 features such as message-driven beans, web services implementation, declarative component security, clustering, component pooling, and stateful components with Spring features such as strong AOP (using tools like AspectJ), POJO injection, productive helper classes, Java Persistence API(JPA) integration, and resource integration.

You can use either of the following two methods to leverage Spring effectively in J2EE applications using EJB 3.0 components:

  1. Use Spring as a general IoC-AOP container, and then integrate EJB components as regular beans to implement business functionality.
  2. Use Spring as a provider of EntityManager for the underlying JPA implementation. In this case, Spring goes beyond basic container support to manage the state of the EntityManager and ensure compatibility with third-party JPA providers, automatic participation in transactions, exception handling, and so on.

The application example in this article explains how you can implement method #2 in a solution. It uses Hibernate as the JPA implementation.

The Application Example
The example is a simple web application that simply demonstrates the integration of components with read/update operations. Its only functions are accepting a user’s ID as input, returning the user’s profile, and allowing the user to update the profile. While the general instructions to follow are based on using Eclipse, they should apply to other IDEs as well. (The application is available with the downloadable code.)

First, you need to set up the component model for the application with these steps:

  1. Create an enterprise J2EE project called Account and create a web project in it called AccountWeb.
  2. Add the Java EE 5 libraries (javaee5.jar) of your application server to the build path.
  3. Create a directory called “lib” under the EAR project where you will place all the application JARs. All projects in the EAR will refer to these libraries.

Click to enlarge

Figure 1. Overall Component Model:
Here is the component model for the application example.

Next, you build the presentation tier by creating an index.jsp page and using Spring MVC to hook it up to the appropriate controller and the response page (refer to Figure 1). To complete a standard MVC configuration, add the URL mapping and view resolver to the configuration file springapp-servlet.xmlas follows:

   			springAppController	      	org.springframework.web.servlet.view.JstlView      	       	 .jsp    

Next, initialize springapp-servlet.xml through the web.xmlas follows:

springapp    org.springframework.web.servlet.DispatcherServlet

Your web project tree should look like Figure 2now.

Click to enlarge

Figure 2. Web Project Tree:
Here is how your web project tree should look.

At this point you can transition from the presentation tier to the business tier, where you will implement the business logic for the application example as a stateless session bean.

Invoking EJB 3.0 Stateless Session Beans
The traditional approach for invoking stateless session beans (SLSB) has been implementing the service locater pattern and then referencing the local (or remote) interface. EJB 3.0 makes the whole invocation process as easy as adding an annotation (@EJB) in the calling class. Note: For local interfaces, GlassFish requires you to provide name and bean interfaceparameters (for example, name=”profejbref”, beanInterface=com.app.domain.ejb.ProfileManager.class) and look up the local EJB reference in the private namespace (java:comp/env). Local EJBs are not registered in the global JNDI. Not all application servers require this.

To enable Spring to seamlessly include the SLSB in the application example’s presentation tier controller, you configure it down to a Spring-managed bean. Simply add the following entry in the Spring application context file applicationContext.xml, which is located in the WEB-INF directory:

	  

With the following snippet, you now inject the above Spring-managed EJB into the controller class and declare it in springapp-servlet.xml, just like any other Spring dependency injection wiring, with the reference being available through a getter method:

								

Note that the presentation tier has no references to EJBs or any other constructs. All these references are taken out to the Spring configuration file. A remote EJB 3.0 SLSB can be looked up easily in the global JNDI, which the container uses to register remote SLSB.

The Spring Pitchforkproject is an attempt to provide support for the Java EE 5 programming model, which includes support for EJB annotations. It currently supports WebLogic application server, but hopefully it will offer full-featured support and integration with all application servers in the near future. Until then, you can use the above process.

Building the Domain Tier with EJB 3.0 Stateless Session Beans
To build the domain tier for the application example, create a new Java project and name it AccountEJB. Again, remember to include the Java EE 5 library to the build path. To see the effectiveness of Spring injection in action, you will use a SLSB with a remote interface for this project. Create an interface class for a business implementation bean called ProfileManager as follows:

import javax.ejb.Remote;import com.app.domain.entity.Profile;@Remotepublic interface ProfileManager {	public Profile getProfile(String id);		public long setProfile(Profile p);}

This is nothing but a plain old Java interface (POJI) with an @Remoteannotation added to indicate that you are going to create a remote interface for the SLSB.

Next, you create a POJO class that implements this interface and the methods in it. This is the class where you implement your business logic. After adding logic to the method, all you have to do is add an annotation (@Stateless) to make it an SLSB. You can use the optional element mappedName if you want the JNDI name to be different from the default. You can add it in the deployment descriptor or in the annotation as follows:

@Stateless(mappedName="ejb/ProfMgrEJB")public class ProfileManagerEJBImpl implements ProfileManager {   ... }

Just by adding two annotations and no configuration, you have taken a simple POJO implementation class and non-intrusively transformed it into an EJB 3.0 stateless session bean. When deployed, the container will recognize the annotations and deploy the class in the EJB container with the appropriate default attributes, including the JNDI name–all without touching configuration files or creating Local, Home, and other classes.

If you are more comfortable with configuration files than with annotations, you can achieve the same result by adding the following to the ejb-jar.xmlin the META-INF directory of the AccountEJB project:

   ProfileManagerEJBImpl    com.app.domain.ejb.ProfileManager    ejb/ProfMgrEJB    com.app.domain.ejb.impl.ProfileManagerEJBImpl    Stateless

You successfully created the SLSB, but to use Spring in the EJB container you first need to create a separate application context file for the domain tier. This is necessary because the EJB is deployed in a separate container outside of the Web container and the EJB container will not recognize any context initialized in the web container. Also, creating a separate application context file is a good practice given the fact that you have separated your domain in a distinct project called AccountEJB because the context of domain should be independent of the presentation.

So create a new file called domainContext.xml under the project source directory. You will use the EJB deployment descriptor to initialize this context file. Also, create a new file ejb-jar.xmlunder the META-INF directory of the AccountEJB project, and add the following to initialize the Spring context in the domain tier:

   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_3_0.xsd">	   	         ProfileManagerEJBImpl         com.app.domain.ejb.ProfileManager         com.app.domain.ejb.impl.ProfileManagerEJBImpl         Stateless         		ejb/BeanFactoryPath		java.lang.String		domainContext.xml		         

This code basically initializes the Spring context in the EJB tier as a environment variable for the SLSB using domainContext.xml.

To invoke beans instantiated by domainContext.xml from the POJO EJB class, extend a Spring helper class AbstractStatelessSessionBean and, using the onEjbCreate()method in the class, explicitly invoke the bean reference as follows:

public class ProfileManagerEJBImpl extends AbstractStatelessSessionBean implements ProfileManager {	private ProfileDao profileDAO;	public Profile getProfile(String id) {		Profile pro = profileDAO.getProfile(id);		return pro;	}	public long setProfile(Profile p) {		return profileDAO.setProfile(p);	}	protected voID onEjbCreate() {  	   profileDAO = (ProfileDao)getBeanFactory().getBean("profileDAO");	}}

The next section will elaborate on the bean profileDao while discussing domainContext.xmland the Spring context in an EJB container.

You use Spring in the domain tier not only to avail the usual benefits, but also to give yourself the option of implementing persistence using the JPA-compliant Hibernate tool (the next section shows how). You will use the EJB that you implemented as a POJO in EJB 3.0 to execute business logic and to persist data to the database using the EJB 3.0 ORM solution, JPA.

Implementing Hibernate JPA Using Spring
EJB 3.0 comes with JPA, a robust ORM-based persistence solution. Because it is an open standard, JPA allows developers to choose an alternate implementation using a JPA-compatible tool. Hibernate is one such tool. Spring has traditionally supported Hibernate with its DAO support classes and recently started supporting JPA. You will combine these into a Spring-driven JPA implementation using Hibernate.

Of course you can use a container-supported JPA implementation, but you would forgo significant added features that Hibernate offers. Hibernate’s configuration-based features such as locking, caching, and dynamic updates can provide substantial value in terms of productivity and performance without tying the application code to Hibernate. If portability is not necessarily a concern, Hibernate also provides a slew of options in its API, mappings, and annotations that go far beyond what JPA provides for integrating with complex enterprise databases.

Hibernate also benefits from integrating with JPA as opposed to being a standalone implementation. The significant value-adds of being in a Java EE container include portable queries, integration into a life cycle with other application components, automatic transaction demarcation, automatic detection of annotated classes, ease of deployment, and consistent interfaces.

Using Spring to implement persistence though Hibernate not only provides Spring features such as interceptors, extensive AOP support, product integration, granular transactions, and non-intrusive lightweight dependency management, but it also allows you to transparently leverage the features of Hibernate’s strong, specification-based ORM implementation. To begin, create the Listing 1 entry in domainContext.xml. Here is a quick explanation of the significant elements:

  • The “entityManagerFactory” ID is used to create an entity manager, which the DAO classes subsequently will use for persistence.
  • The EntityManager instance in JPA is used to manage the life cycle of entities within a persistence context. It basically finds entities with keys, creates them, and removes them.
  • It is also used to execute queries. You leverage LocalContainerEntityManagerFactoryBean, a Spring wrapper, to instantiate the JPA EntityManager and provide other fine-grained options such as custom JPA providers.
  • This is where you declare your intention to use Hibernate as your JPA service provider and set its properties.
  • The database dialect is configured through the “databasePlatform” parameter. (Optionally, for popular databases you can also add the parameter “database.” For more information, see JavaDocs of org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter.)
  • The entry also takes a datasource as a parameter. The datasource can be either procured through JNDI or, as in this case, declared locally.
  • There is also an optional entry for loadTimeWeaver, which is set specifically to the container and is sometimes required if the persistence provider insists on support for byte-code transformation. Hibernate does not require such an entry.
  • The entry also declares a transaction manager and enables annotation-based transaction support in your classes. It looks for the @Transactional tag. PersistenceExceptionTranslationPostProcess is a Spring value-add used to facilitate exception translation to a provider-specific exception instead of the standard JPA exception hierarchy. It looks for the @Repository tag.
  • The JPA specification requires the presence of a file called persistence.xml in the META-INF directory. This file is typically where you would have added the reference to a Hibernate implementation and added Hibernate-specific properties. However, because Spring has taken over the function of supporting a JPA vendor, all entries go in the domainContext and you can ignore them here.

Your file ends up looking as follows, with only the definition of a persistence unit name:

        

You will also define an entity class called com.app.domain.entity.Profile, which is nothing but a POJO. You can instantiate it with new. It is a non-abstract, concrete class that has no dependencies on anything related to the container. You can wholly specify the persistence nature of the entity by using annotations. The following are the significant parts of the class:

@Entity@Table(name="APP.PROFILE")public class Profile implements Serializable{	@Id	@Column(name="PROFILEID")	private String id;	 @Column(name="FNAME")	private String fname;	 @Column(name="LNAME")	private String lname;	 @Column(name="ADDRESS")	private String address;	 @Column(name="EMAIL")	private String email;      // bunch of getters/setters      ...}

The declaration @Entity has denoted this as a class that will be persisted. The @Table definition lists the table name of the database referenced. The @IDfield denotes the primary key of the table, and all other annotations map the class variable to the corresponding database column. This class is fully self sufficient, and you can persist it. You will use it to build a relationship with the database, carry data to and from the database, and (because it’s a POJO) pass around information across tiers.

Now you’re at the implementation of the Data Access Object (also called the Entity Access Object) class, which is responsible for the actual actions related to persistence. At this point, you have a couple of choices:

  1. You can implement the whole class with standard JPA constructs, completely independent of Spring.
  2. You can leverage Spring and use its JPATemplate class through its JpaDaoSupport helper class.

If you choose not to use JPATemplate, the EntityManager is passed on to the DAO using the annotation @PersistentContext. In a regular JPA, the container would populate the EntityManager using dependency injection. In this case, Spring plays that role. Spring recognizes JPA constructs such as @PersistentContext and injects the EntityManager just like the container. The PersistenceAnnotationBeanPostProcessor, declared in Spring context, helps with the JPA annotation processing. However, even though the code is independent of any Spring classes, it also means that the DAO now has to worry about the EntityManager life cycle and transactions. Spring can still help in granular transaction management using the @Transactionalannotation. The class com.app.domain.dao.impl.HibernateProfileDaoNonTmpl shows an example of such an implementation.

For your implementation, you will extend the Spring JpaDaoSupport helper class and use the JPATemplate provided as getter/setter methods. The JPATemplate, in the tradition of HibernateTemplate and JDBCTemplate, takes over the responsibility of managing the state of EntityManager, automatically participates in transactions, and manages exceptions. It also offers all the underlying methods supported by JPA and provides some more convenient methods to improve productivity. It is thread-safe as well, and you can use it as an instance variable.

The declaration and the DAO code look like this:

@Transactionalpublic class HibernateProfileDao extends JpaDaoSupport implements ProfileDao {    	public Profile getProfile(String id) {		 Profile pro = getJpaTemplate().find(Profile.class, id);		 		return pro;	}	public long setProfile(Profile p) {		if (p.getId() == null) {            // insert new record			getJpaTemplate().persist(p);        } else {            // update existing record after a read        	getJpaTemplate().merge(p);        }		return 0;	}}

Again, the @Transactionalnotation ensures transaction management and commits/rollbacks.

The resulting EJB domain project tree should look like Figure 3.

Click to enlarge

Figure 3. EJB Domain Project Tree:
Here is how your EJB domain project tree should look.

Deployment and Testing
After creating the database records in the App.PROFILEtable, start up the database and the application server. You will use GlassFish as your application server for deployment. After the project Account.ear successfully deploys as an enterprise archive with the EJB and the web modules, you will see the JNDI entry for the remote SLSB in the JNDI browser provided by the GlassFish console. If Spring didn’t find the JNDI entry or any other injection elements, it will give a deployment time error.

The application retrieves the profile of a user based on an ID and updates it. For the read and update, you can see the following output:

ReadHibernate: select profile0_.PROFILEID as PROFILEID0_0_, profile0_.ADDRESS as ADDRESS0_0_, 
profile0_.EMAIL as EMAIL0_0_, profile0_.FNAME as FNAME0_0_, profile0_.LNAME as LNAME0_0_
from APP.PROFILE profile0_ where profile0_.PROFILEID=?|#]
UpdateHibernate: update APP.PROFILE set ADDRESS=?, EMAIL=?, FNAME=?, LNAME=? where PROFILEID=?|#]

Best Practice Tips
As a simple implementation to demonstrate using Spring, EJB 3.0, and Hibernate, the application example includes a few compromises in its architecture and layout. In a real world enterprise application, you should further split the EJB project into a separate domain project (possibly called AccountDomain) and place the classes beyond the EJB in it. This would allow for further separation between the container-specific component implementation like EJB and a purely POJO-based domain. So if the application requirements change at all in the future, the EJB can be cleanly eliminated.

Also, it is always a good idea to implement the Business Method Interface pattern when using remote interfaces in enterprise applications. If the Remote interface class and the Bean implementation class respectively extend and implement a single POJI class, you end up with a robust mechanism wherein the POJI business interface defines the business functions while the Remote interface exposes them and the Bean class implements them. This approach prevents the natural disconnect between the business methods, the Remote EJB interface, and the implementation.

EJB 3.0, Spring, or Hibernate: Why Not All Three?
You have seen how you can leverage tools like Spring with the new EJB 3.0 component architecture. You’ve also seen how you can implement EJB 3.0 JPA using Hibernate and effectively integrate it with the EJB-based domain tier using Spring. EJB 3.0 by itself is a strong architecture that provides the features found in Spring and Hibernate, but now you have an alternative for circumstances that fit the need. Spring has a ways to go to fully support the EJB 3.0 architecture, which will make a few things discussed here easier. The Spring Pitchfork project is an encouraging step in that direction.

devx-admin

Share the Post: