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?