EntityManagers and DAOs
chrismeadows Nov 9, 2006 10:40 AMMy scenario is that I don't want to do my entity manager interaction in a session bean - I want to use a layering approach that has Session beans <-> Business Delegates <-> DAOs <-> JPA entities.
I'm getting frustrated that I cannot inject an entity manager into a DAO class inside the ejb container becasue it is not an EJB. I could use a jndi lookup, but then I jhave to worry about closing the entity manager.
What I really want is to be able to access the EntityManager that was injected into the session bean that was my entry point to the container, but
I do not want to pollute my BD and DAO API's with entity manager parameters.
So, can I use ThreadLocal's? Do the folk at JBoss have a paradigm for doing this, or am I doing something completely stupid?
The example code that follows is significantly trimmed. I've also left out the BD, and ignore the fact that a JPA entity is being returned to the client.
I have a session bean with a simple getter method to load an entity. It delegates to a DAO
@Stateful @Remote public class StatefulColumnGroupServiceBean { @PersistenceContext(unitName="MyApp", type=PersistenceContextType.EXTENDED) protected EntityManager em; public ColumnGroupEntity getColumnGroup(int iThreadNumber, long id) throws ServerException { EntityManagerResource.getInstance().set(em); ColumnGroupEntity cgvo = null; try { cgvo = ColumnGroupDAO.getInstance().getColumnGroup(id); } catch (DAOException e) { log.error(e); throw new ServerException( MessageFactory.getMessage("Bean.CannotFind", "ColumnGroup") + id, e ); } return cgvo; } }
The DAO is
public class ColumnGroupDAO { public ColumnGroupEntity getColumnGroup( long id ) throws DAOException { EntityManager em = EntityManagerResource.getInstance().get(); ColumnGroupEntity res = null; try { res = em.find(ColumnGroupEntity.class, id); } catch (RuntimeException e) { throw new DAOException(MessageFactory.getMessage("DAO.FindError", getClass().getName()) + id, e); } return res; } protected ColumnGroupDAO() { } public static ColumnGroupDAO getInstance() { if( instance == null ) { synchronized( ColumnGroupDAO.class ) { if( instance == null ) { instance = new ColumnGroupDAO(); } } } return instance; } private static ColumnGroupDAO instance = null; }
and the EntityManager is passed between bean and DAO by using a singleton ThreadLocal wrapping an EntityManager instance
public class EntityManagerResource extends ThreadLocalResource<EntityManager> { private static EntityManagerResource instance = null; public static EntityManagerResource getInstance( ) { if( instance == null ) { synchronized( EntityManagerResource.class ) { if( instance == null ) { instance = new EntityManagerResource( ); } } } return instance; } protected EntityManagerResource() { } } public abstract class ThreadLocalResource<T> { private final ThreadLocal<T> resource = new ThreadLocal( ); public void set( T em ) { resource.set(em); } public T get( ) { return resource.get(); } }
Does this make sense? Any suggestions?