I am using Glassfish v3 server.
Usually the DB connection with EJB3 + JPA (Eclipselink) is done through injection, with @PersistenceUnit or @Persistencecontext.
However, there are 3 layers in my App :
-
Core (contains business logic, entities, exception handling etc)
-
an EJB on top of it, calling the right core objects and methods to do the job. This EJB is called by other internal modules of our ERP.
-
a REST layer on top of it for uses by frontend web sites.
I do not want to get the entityManager, nor the EMF (EM factory) in the EJB, because I want my middle layer to be unaware that there is a DB used under it. I could after all, later, decide to change my core implementation for a non-DB-using one.
I see only two bad solutions :
-
1) Add an EM parameter every time i call a method of the core layer that needs DB connection. Very ugly and goes againt what I said above.
-
2) In every method of core needing DB connection, I create a factory, an EM, use them, and then close them both.
I tried to cut things in the middle, having one factory per class of the Core level, and EMs are created and closed in every method. But I still have memory leaks like this :
javax.servlet.ServletException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
I guess it’s because if one of my EJB methods uses 10 different objects, it creates 10 EM factories, and none of them is closed.
Example of typical use in a Core object:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// do some stuff with em; for example persist, etc
em.flush();
em.close();
Should I go for solution 2?
Is there a way to use a single EM factory at this core level ? I seems like the JPA spec assumes you’re going to use the entities at the EJB level only, which is bad in a multi layers apps.
EDIT : here is the current status after trying @Inject :
-
Added an empty beans.xml file in the /META-INF directory on my CORE jar.
-
The parent DAO class is now like this :
public class ExampleBZL {
public EntityManagerFactory emf; @Inject public Emf emfobject; public ExampleBZL() { this.emf = emfobject.emf; } -
The Emf class is very simple, and Stateless.
@Stateless
public class Emf implements EmfAbstract {@PersistenceUnit(unitName = Setup.persistenceUnitName) public EntityManagerFactory emf; public Emf() { }}
I must be doing something wrong, but the injection doesn’t work, altough in glassfish I see “[ejb, weld, web]” in the engines list, so the CDI is loaded.
Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
at com.blablabla.core.bizlogic.ExampleBZL.<init>(ExampleBZL.java:40)
Am I missing other annotations ?? Is it really working to do an inection in a JAR with those two small annotations (Stateless on one side, Inject on the other) ?
What if you had two session beans? One with the injected EntityManager that can leverage JTA, and the other is your current session bean.
I am currently putting together a series on my blog using a session bean as the REST service using EclipseLink & Glass Fish v3:
Below is how I inject the EntityManager on my session bean that is serving as my REST service:
You can link your session beans using the @EJB annotation: