March 28, 2008

An ORM-pattern merger

In today's post I will describe a pattern which I used in two projects so far and right now I don't really see a reason why I shouldn't use it again, I call it Generic EAO pattern. In fact, it's a merger of two patterns, namely the Generic DAO pattern which one of my former co-workers presented to me a couple of years ago and which he subsequently published on developerWorks. The other pattern is the Entity Access Object pattern presented in the book EJB 3 in Action.

I can quickly describe both patterns. The Generic DAO pattern uses Java Generics so you don't have to repeat the same CRUD-code over and over again to handle Entities. It's made for Hibernate but as you will see later, it works equally well in JPA.

The EAO pattern basically introduces an extra layer of abstraction. There are lots of discussions all over the internet whether the DAO (or in our case: EAO) pattern has died with the inception of EJB 3.0, where you can simply inject an EntityManager to your EJBs. Personally I have mixed feelings about it but I do accept the main argument given by the book, namely: What if you ever want to change persistence technology? You will probably end up rewriting all your EJBs.

However, the pattern as shown in the book left me wondering if I am not just writing lot's and lot's of code for nothing and thus the idea of merging two patterns was born.

So let's get started right away...

First of all, we need a generic interface for our EAO:

public interface BaseEAO<T, PK extends Serializable> {
void create(T t);

T read(PK pk);

T update(T t);

void delete(T t);

T refresh(T t);
}
Subsequently we build a generic EAO superclass:

public abstract class GenericEAO<T, PK extends Serializable> implements BaseEAO<T, PK> {
private static final String ENTITY_MANAGER_NAME = "java:comp/env/myPU";
private Class<T> type;
protected EntityManager em;

public GenericEAO(Class<T> type) {
this.type = type;
this.em = getEntityManager();
}

public void create(T t) {
em.persist(t);
}

public T read(PK pk) {
return em.find(type, pk);
}

public T update(T t) {
return em.merge(t);
}

public void delete(T t) {
em.remove(em.merge(t));
}

public T refresh(T t) {
if (!em.contains(t)) {
t = em.merge(t);
}
em.refresh(t);
return t;
}

protected EntityManager getEntityManager() {
try {
InitialContext ctx = new InitialContext();
return (EntityManager) ctx.lookup(ENTITY_MANAGER_NAME);
} catch (NamingException e) {
System.out.println("Unable to obtain EntityManager. This call will fail!");
return null;
}
}
}
In fact, if this class wouldn't be declared abstract, you'd be good to go already (provided the class using it has a type-level @PersistenceContext annotation, I'll explain this later, though...).

Create an interface for the EAO which we create in just a second:

public interface FieldEAO extends BaseEAO<Field, Integer> {
List<Field> findAllByType(String type);
}
And now let's implement an actual EAO which can be used in a Session Bean.:

public class FieldEAOImpl extends GenericEAO<Field, Integer> implements FieldEAO {
public FieldEAOImpl() {
super(Field.class);
}

public List<Field> findAllByType(String type) {
Query q = em.createQuery("select f from Field f where f.type = :type");
q.setParameter("type", type);
@SuppressWarnings("unchecked")
List<Field> list = q.getResultList();
return list;
}
}
As you can see, we didn't redo all the CRUD-operations, however, we did add a findAllByType-method which is specific to this Entity.

Now this is starting to look like something useful, however, we aren't quite there yet. Since all the classes so far are simple POJOs, the EntityManager-lookup in the InitialContext would fail. Why? Well, no persistence context has been created. We can do this by the previously mentoined type-level annotation. We localize this to a Stateless Session Bean which coincidentally also works as a factory, an EAO factory, to be specific:

@Stateless
@PersistenceContext(name = "myPU", unitName = "myPU")
public class EAOFactoryBean implements EAOFactory {
public FieldEAO getFieldEAO() {
return new FieldEAOImpl();
}
}
And naturally we need a local interface for this bean:

@Local
public interface EAOFactory {
FieldEAO getFieldEAO();
}
As you can see, the bean uses the @PersistenceContext annotation, which creates the persistence context for the EAO to use it.

Finally, some EJB might want to use it:

@Stateless
public class FieldFacadeBean implements FieldFacade {
@EJB
private EAOFactory eaoFactory;

public void createField(Field f) {
FieldEAO eao = eaoFactory.getFieldEAO();
eao.create(f);
}

public List<Field> findAllByType(String type) {
FieldEAO eao = eaoFactory.getFieldEAO();
return eao.findAllByType(type);
}
}
And it's local interface:

@Local
public interface FieldFacade {
public void createField(Field f);

public List<Field> findAllByType(String type);
}
Well, that's about it. Thanks to the excessive use of interfaces and the factory, you will easily be able to replace the JPA-specific implementation with any other data-access implementation

Note that you may want to expose the EntityManager's flush() method in the GenericEAO-class since there are cases where you may need it and there isn't any other way to get the EntityManager in the current design.

I definitely wouldn't consider it a best practice just yet and this pattern definitely has imperfections. If you have suggestions, questions or criticism, I'd love to know about it so leave a comment.

NOTE: Erik asked in a comment whether all entities will be detached. After getting a little uncertain if there is a previously undiscovered flaw in the pattern I set up a little test case and it does behave as expected. While the entities are in the scope of a transaction they will remain attached until the transaction commits (or aborts).

3 comments:

Anonymous said...

Hi, I'm currently using your'e pattern in a project, and it works greate! Nice to see some concret examples of using the EAO! Thanks.

Daniel said...

That's good to hear. I am actually planning to refine the pattern a little bit before my next project so check back in a couple of weeks for some updates :)

Erik said...

I will! :) Just a quick question. In "EJB 3 in Action" the use of a Session Facade is descibed. Just wondering if you use that with the pattern, and if so, how do you handle detatchment? With your pattern the entites are detatched when they are returned (right?). Would using an EntityManager in the facade, and merging there be a solution? Thinking in particular about retriving lazy loaded references etc.