Using the Java Persistence API with Spring 2.0

by Seth White
03/20/2006

Using DAOs to Implement Services 

Now that we've seen how data access objects are implemented using Spring 2.0 and JPA, let's take a quick look at a MedRec service object that uses a DAO to do its work. The following code sample shows the PatientServiceImpl class and one of its business methods, the processNewRegistration method:


public class PatientServiceImpl 

   extends BaseService implements PatientService {

 

    protected PatientDao patientDao;



    public void setPatientDao(PatientDao patientDao) {

        this.patientDao = patientDao;

    }

    

    public void processNewRegistration(Registration registration) {

      try {

         User user = registration.getUser();

         Patient patient = registration.getPatient();

         patient.setUser(user);

         user.setStatus(MedRecConstants.USER_NEW);

            

         patientDao.save(pPatient);

      } catch (Exception ex) {

        ...

      }

   }

   

   ...

}

The processNewRegistration method is invoked when a new patient self-registers using the MedRec Web interface. It takes as a parameter a Registration object that holds the registration information for the new patient. ProcessNewRegistration first gets a Patient and User from the Registration object and initializes the relationship between them. The User object contains username and password information for the patient, as well has the patient's status which is set to USER_NEW since this is a new patient that must be approved by an administrator. Then, the Patient DAO is invoked to insert the new patient into the database.

Spring declarative transactions are configured for the MedRec service objects so that a transaction is started by Spring before a business method like processNewRegistration is invoked and committed when the method completes. This insures that the DAO does its work as part of an existing transaction that can be committed atomically. Also note the setPatientDao method which is used by Spring to inject the reference to the DAO object into our service bean.

Configuration

So far, we've looked at some of the Java code that makes up this version of the Medical Records application. This section will give you an idea of the external configuration that is required by Spring and Kodo. We will begin with Spring.

Spring configuration

The Spring ApplicationContext is configured using a set of modular XML configuration files. The configuration file containing the data access object's configuration is applicationContext-orm.xml, which is located in the src\medrecEar\APP-INF\classes directory under the MedRec installation directory. Here is the stanza in applicationContext-orm.xml that declares the Patient DAO:


<bean id="patientDao"

      class="com.bea.medrec.dao.orm.JpaPatientDao"

      autowire="byType"/>

Spring's JPA DAOs have a single dependency that needs to be injected. This is the JPA EntityManagerFactory. The EntityManagerFactory is used by the DAO to create JPA EntityManagers that perform the actual persistence work. The wiring here is done using the Spring autowire feature, which is why we don't see the dependency on the EntityManagerFactory explicitly in the XML. The autowire feature automatically wires the DAO to the EntityManagerFactory based on the type of the DAO's EntityManagerFactory property which is inherited from the Spring JpaDaoSupport class that all of the MedRec DAO classes extend.

The code below shows the stanza that declares the Spring factory bean that creates the EntityManagerFactory. Since there are two factories being discussed here, things may sound confusing, but keep in mind that the purpose of the Spring factory bean is simply to provide a level of indirection that allows us to execute some custom code to create the EntityManagerFactory. The EntityManagerFactory is the only factory that the DAO objects know or care about.


<bean id="entityManagerFactory"

      class="com.bea.medrec.utils.KodoEntityManagerFactoryBean">

  <property name="jndiName">

     <value>kodo-jpa</value>

  </property>  

</bean>

The EntityManagerFactory is created using a custom factory bean since at the time of this writing WebLogic Server does not support standard integration with JPA. The EntityManagerFactory needs to know where to look up the Kodo resource adapter in JNDI. This information is configured as a property on the Spring factory bean which passes it along to the EntityManagerFactory. Remember, the job of the factory bean is to create an EntityManagerFactory instance and return it to Spring so that Spring can inject the EntityManagerFactory into the DAO beans. The code for the factory bean that creates the entity manager factory instance looks like this:


public class KodoEntityManagerFactoryBean 

   implements FactoryBean, InitializingBean {



   private String jndiName = "kodo-jpa";



   private EntityManagerFactory entityManagerFactory = null;



   public void setJndiName(String jndiName) {

      this.jndiName = jndiName;

   } 



   public Object getObject() throws Exception {

      return entityManagerFactory;

   }



   public Class getObjectType() {

      return EntityManagerFactory.class;

   }



   public boolean isSingleton() {

      return true;

   } 



   public void afterPropertiesSet() throws Exception {

      try {

         entityManagerFactory  =

            KodoPersistence.createEntityManagerFactory(

               jndiName, new InitialContext());

      } catch (Throwable throwable) {

         throw new RuntimeException(throwable);

      }

   }

}

The KodoEntityManagerFactoryBean is a fairly straightforward Spring factory bean. At runtime, Spring first invokes the default constructor to create an instance of the bean. Then, Spring calls the setJndiName() method to set the JNDI name of the Kodo resource adapter. Once all properties have been injected, Spring calls afterPropertiesSet(), which creates the EntityManagerFactory instance. Finally, Spring calls getObject() to get the EntityManagerFactory that will be injected into our DAOs.