UserTransaction in servlets - jpa

I wonder if it is ok to use UserTransaction like in this scenario below.
EntityManager is not thread-safe so there is helper class.
public class EMProducer {
#PersistenceContext
EntityManager em;
#Produces
#RequestScoped
public EntityManager createEM() {
return em;
}
}
and the Servlet:
#WebServlet("/test")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject
EntityManager em;
#Resource
UserTransaction utx;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyEntity entity = new MyEntity("test entity");
//try...
utx.begin();
em.persist(entity);
utx.commit();
//catch...
}
}
The problem is that there is always the same instance of UserTransaction object injected. Is it ok or it should be done differently? Is the UserTransaction thread-safe?
When I use BMT EJBs there is also always the same UserTransaction instance injected so I think it is, but I would like to be sure how this works.
(I know about EJBs, #Transactional, that I shouldn't add business logic to servlets etc. but I'm asking about this use case)

Related

#Inject - UserTransaction throws weld error

Error:
Exception 1 :
org.jboss.weld.exceptions.DefinitionException: WELD-001451: javax.transaction.UserTransaction cannot be injected into an enterprise bean with container-managed transactions: [BackedAnnotatedField] #Inject com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction
at com.evry.integrator.snow.model.dao.impl.GenericDaoImpl.userTransaction(GenericDaoImpl.java:0)
StackTrace
at org.jboss.weld.module.ejb.WeldEjbValidator.validateInjectionPointForDefinitionErrors(WeldEjbValidator.java:40)
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDefinitionErrors(Validator.java:336)
Code:
public abstract class GenericDaoImpl<T, PK> implements GenericDao<T, PK> {
private static final Logger LOG = Logger.getLogger(GenericDaoImpl.class.getName());
#PersistenceContext(unitName = "IntegratorMasterdataDS")
protected EntityManager em;
#Inject
UserTransaction userTransaction
Scrutiny Class
#Stateless
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
statusDao.beginUserTransaction(); <--- Here i want to begin
statusDao.create(js);
statusDao.flush();
statusDao.commitUserTransaction(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
Status Dao:
public interface StatusDao extends GenericDao<JobStatus, String> {
List<JobStatus> checkExistingRecordToday(JobName jName);
}
Job Status Dao:
#Stateless
public class JobStatusDaoImpl extends GenericDaoImpl<JobStatus, String> implements StatusDao {
private static final Logger LOG = Logger.getLogger(JobStatusDaoImpl.class.getName());
#Override
public List<JobStatus> checkExistingRecordToday(JobName jName) {
As of now whole process is handled by JTA but i want to commit Scrutiny class instantantly which suggest job has just started and at end want to update the same.
You should remove the UserTransaction injection from your DAO generic object and handle the transaction within Scrutiny bean, annotating it with TransactionManagement.
Your bean code should become this:
#Stateless
#TransactionManagement(value=TransactionManagementType.BEAN)
public class Scrutiny {
private static final Logger log = Logger.getLogger(Scrutiny.class.getName());
#Inject
private UserTransaction utx;
public Scrutiny() {
System.out.println("Scrutiny");
}
#Inject
StatusDao statusDao;
public JobStatus insertNewRecord(JobName jName) {
log.info("insertNewRecord:" + jName);
try {
utx.begin(); <--- Here i want to begin
statusDao.create(js);
utx.flush();
utxcommit(); <--- Here i want to Commit
} catch (Exception e) {
log.warning("insertNewRecord:" + e);
}
}
With these changes, your DAO should continue to work using container managed transactions, while your specific bean can control the transaction as desired.

Is it possible to pass EntityManager as a parameter through multiple beans?

I know i can do the following :
public class MyDao{
private EntityManager em;
public void setEm(EntityManager em){
this.em = em;
}
...
and then, using #PostConstuct to pass the EntityManager
public class MyBean{
private EntityManager em;
#Inject
private MyDao myDao;
#PostConstruct
private void init(){
myDao.setEm(em);
}
...
But due to my application's architecture restriction i cannot directly inject MyDao into MyBean, i should pass by MyBusinessDao Class, so i tried the following but i'm getting a nullPointerExeception on the value of EntityManager in MyDao :
public class MyBean{
private EntityManager em;
public MyBean(){
em = createEntityManager();
}
private EntityManager createEntityManager(){
//dynamically create the EntityManager
}
#Inject
private MyBusinessDao myBusinessDao;
#PostConstruct
private void init(){
myBusinessDao.setEm(em);
}
...
and in MyBusinessDao i inject MyDao:
public class MyBusinessDao {
private EntityManager em;
#Inject
private MyDao myDao;
#PostConstruct
private void init(){
myDao.setEm(em);
}
...
I should mention that i'm not using a J2EE container
You can implement an CDI Producer Method for providing the EntityManager via CDI injection.
#ApplicationScoped
class EntityManagerProducer {
#PersistenceContext(...)
private EntityManager em;
#Produces
#RequestScoped
public EntityManager produceEm() {
return em;
}
}
You can also inject the EntityManagerFactory and call emf.createEntityManager() in the producer method and implement an CDI-Disposer method, which closes the EntityManager before the scope is finished.
public void dispose(#Disposes EntityManager em) { ... }
If you have multiple persistence contexts, then implement a producer method for each persistence context and qualify them with a CDI-Qualifier.
I resolved it this way :
public class MyBusinessDao {
private EntityManager em;
#Inject
private MyDao myDao;
private void setEm(EntityManager em){
this.em = em;
//and here i call the setEm method of myDao also
myDao.setEm(em);
}
...

Arquillian #BeforeClass injected EntityManager null

I'd like to persist some data using an instance of an EntityManager using Arquillian. To do so I'd like it to be done once before all the tests, so I tried using #BeforeClass like so
#RunWith(Arquillian.class)
public class MyTest {
#Deployment
public static WebArchive createDeployment() {
// create deployment
}
#PersistenceContext
static EntityManager em;
#BeforeClass
public static void setup() {
em.persist(someObject);
}
}
Using this approach however the EntityManager is null. I can get this to work with #Before but obviously this runs before every test method which I don't want.

CDI with EntityListener and timing issue?

I'm trying to do this.
public class MyEntityListener {
#PrePersist
private void onPrePersist(final Object object) {
// set object with value fetched via onPostConstruct
}
#PostConstruct
private void onPostConstruct() {
// fetch some value using entityManager
}
#PersistenceContext
private EntityManager entityManager;
}
When I persist and instance via EJB, the entityManager is different instance from that of the EJB.
onPrePersist is executed (before or) regardless of postConstruct.
Is this normal?

CDI EntityManager fail

Hibernate says "An exception thrown by Hibernate means you have to rollback your database transaction and close the Session immediately".
When persist method throws a SQLException and the entityManager becomes dirty, if I close the EntityManager, it still in Conversation Scope.
i'm using: tomcat 7, cdi 1.1, hibernate 4.1;
Is there any way to produce a new EntityManager for the current conversation to replace the dirty?
#Produces
#ConversationScoped
public EntityManager create(EntityManagerFactory emf) {
EntityManager em = emf.createEntityManager();
...
ViewBean
#Named #ConversationScoped
public class MyView implements Serializable {
enter code here
#Inject #Getter private EntityManager em;
...
public void persist(){
try{
getEm().getTransaction().begin();
getEm().persist(entityInstance);
getEm().getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
if(getEm().getTransaction().isActive()){
getEm().getTransaction().rollback();
}
}
}
No, there is not. Conversation scoped isn't a very good scope for an EntityManager anyway. It should really be Request or Default due to transaction boundaries.