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.