EntityManager throws TransactionRequiredException on merge() in JBoss JSF bean - java

I've set up a JSF application on JBoss 5.0.1GA to present a list of Users in a table and allow deleting of individual users via a button next to each user.
When deleteUser is called, the call is passed to a UserDAOBean which gets an EntityManager injected from JBoss.
I'm using the code
public void delete(E entity)
{
em.remove(em.merge(entity));
}
to delete the user (code was c&p from a JPA tutorial). Just calling em.remove(entity) has no effect and still causes the same exception.
When this line is reached, I'm getting a TransactionRequiredException:
(skipping apparently irrelevant stacktrace-stuff)
...
20:38:06,406 ERROR [[Faces Servlet]]
Servlet.service() for servlet Faces
Servlet threw exception
javax.persistence.TransactionRequiredException:
EntityManager must be access within a
transaction at
org.jboss.jpa.deployment.ManagedEntityManagerFactory.verifyInTx(ManagedEntityManagerFactory.java:155)
at
org.jboss.jpa.tx.TransactionScopedEntityManager.merge(TransactionScopedEntityManager.java:192)
at
at.fhj.itm.utils.DAOImplTemplate.delete(DAOImplTemplate.java:54)
at
at.fhj.itm.UserBean.delete(UserBean.java:53)
at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
...
I already tried to wrap a manually managed transaction (em.getTransaction().begin() + .commit() ) around it, but this failed because it is not allowed within JBoss container. I had no success with UserTransaction either. Searches on the web for this issue also turned up no similar case and solution.
Has anyone experienced something similar before and found a solution to this?

Found the missing link.
It was indeed a missing transaction but the solution was not to use the EntityManager to handle it but to add an injected UserTransaction.
#Resource
UserTransaction ut;
...
public void delete(E entity)
{
ut.begin();
em.remove(em.merge(entity));
ut.commit();
}
Thanks to all suggestions which somehow over 100 corners lead to this solution.

Know this is an old question, but just in case somebody stumbles on this like me.
Try
em.joinTransaction();
em.remove(bean);
em.flush();
That's what we use in all our #Stateful beans.
If you are using Seam, you can also use #Transactional(TransactionPropagationType.REQUIRED) annotation.

Are you sure that you annotated you bean with #Stateless or register it with xml?
Try add transaction's annotation to you code, this can help you:
#TransactionAttribute(REQUIRED)
public void delete(E entity)
{
em.remove(em.merge(entity));
}
But it seems strange, because this is default value if you don't set it explicitly.

just a note: we ran into this same issue today, turned out someone had marked the EJB as TransactionAttributeType.NOT_SUPPORTED AND the method as TransactionAttributeType.REQUIRED, causing the em.merge to fail for lack of transaction.

Related

Spring integration : Is it possible to implement a Transaction in a ServiceActivator method?

I would like to annotate my ServiceActivator with Transactional as below :
#ServiceActivator
#Transactional(rollbackFor = Exception.class)
public Message<MyResult> populate(List<Things> th) {
// inserting in database
// try { throwing an exception } catch...
//doing other stuffs (insersions)
}
I expect to rollback the insersions after throwing an exception.
Unfortunately it dosen't work, I got the insersions in database.
Thanks in advance.
Just to close this topic, I'm providing the answer here. Even if it looks like hijacking it from Gary Russell. Although we are from the same team.
So, the #Transactional as many other aspects in Spring must be enabled. For this purpose there is a special #Enable... annotation - #EnableTransactionManagement. This one scans for the PlatformTransactionManager bean and applies AOP Advices to the methods marked with the #Transactional.
See Reference Manual for more information.

Handling 'The EJB does not exist' or 'Cannot load from BACKUPSTORE FOR Key'

so the problem is pretty simple:
We are using JSF 2.0 with Primefaces and EJB to handle our application and we have encountered a problem. We have a single #SessionScoped bean in which we store all ours #Stateful Session Beans.
In one case, (when we didn't handle some exceptions from JPA) and there is an exception:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "webuser_idwebuser_pk"
Detail: Key (idwebuser)=(6) already exists.
It leads to destruction of one of our #Stateful Session Bean.
So after refreshing the website, when JSF is still working correctly, after filling the form and trying to submit it, by invoking a method from that Bean there is an exception:
javax.ejb.NoSuchObjectLocalException: The EJB does not exist. session-key: 22900a4d007e1f-6dcc714a-0
What is the most problematic, we have to restart and redeploy the application to make it work on the same computer (or web browser) because the JSF's #SessionScoped Bean is somehow kept through cookies or something.
So the solution I guess would be to force the destuction of that #SessionScoped or refresh the session somehow, but actually I have no idea how to do so.
Or what would be a better approach.
Thanks!
To remedy this, you need to be aware about the difference between application- and system exceptions in EJB.
Those roughly correspond to checked and runtime exceptions respectively.
Application exceptions are supposed to be handled by your own code, and will not cause a transaction rollback or the destruction of a bean. System exceptions have the opposite effect and will cause a rollback and the destruction of the EJB bean.
The latter effect is what you are seeing. JPA throws unchecked exceptions, which thus become system exceptions, which thus cause your SFSB to be destroyed. JSF nor CDI managed beans participate in this "system exception" thing, so they will just propagate the exception and will stay alive.
What you probably want is to define a new Exception that you annotate with #ApplicationException and then set its rollback attribute to true. Catch the JPA exception within your SFSB and wrap and rethrow it with your custom exception.
Ok so I've found the answer on my own.
Actually what I've needed was to handle exceptions in JSF view by extending ActionListenerImpl.
The original article is here:
Original
But what I've done was to extend the exception handling with invalidating the HTTP session which, in the end, ended the life of #SessionScoped Managed Bean and leaded to reinjection of SSBs. Like this:
private void gotoErrorPage(MethodExpression expression) {
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
NavigationHandler navHandler = application.getNavigationHandler();
navHandler.handleNavigation(context, null == expression ? null : expression.getExpressionString(), NAV_ERRORPAGE);
context.renderResponse();
}

Container-managed transaction in JAX-WS, weblogic

I'm trying to use Container-Managed Transactions inside webservice, but transaction isn't created. I have something like that:
#WebService(...)
#Stateless
#TransactionManagment(TransactionManagmentType.CONTAINER)
public class ExampleService {
// EntityManager and other fields
#TransactionAttribure(TransactionAttributeType.REQUIRED)
public void test(String s){
// persist something with EntityManager
}
}
When I call this method, I get javax.persistence.TransactionRequiredException: The method public abstract void javax.persistence.EntityManager.persist(java.lang.Object) must be called in the context of a transaction.
What am I doing wrong?
Thanks!
From what I recall 'TransactionAttributeType.REQUIRED' means that method should be only called when transaction is already in progress for current thread (in other words 'called in context of transaction'). It's not clear who if anybody starts transaction in your case. If nobody then the exception you're getting makes perfect sense.
Now I'm not sure how or is it even currently possible to propagate transaction across Web services call. I don't think this is particularly good idea to do so even if possible.
Perhaps you what you need TransactionAttributeType.REQURES_NEW in your case so Container would start the transaction before passing control to your annotated method?

How to use Eclipselink #Multitenant in JSF/EJB?

The #Multitenant support in Eclipselink 2.3 looks really interesting, but I'm having a hard time understanding how to use it in a JSF or EJB which injects an EntityManager with #PersistenceContext. The EclipseLink docs are pretty clear that #PersistenceContext injection doesn't work in this case, but you could inject an EntityManagerFactory via #PersistenceUunit instead.
Still, what I'm not seeing is how to manage the lifecycle of an EntityManager you might create via injected EntityManagerFactory.createEntityManager() - in particular, when to close the resulting EntityManager, and how to participate in transactions.
Has anyone gotten this to work? Or am I missing something obvious?
See also: http://wiki.eclipse.org/EclipseLink/Examples/JPA/Multitenant
UPDATE
I had some success with #PersistenceContext (EntityManager) injection and then passing parameters to EclipseLink via session listener. I'm not 100% sure this is the right answer and would appreciate confirmation that it isn't creating a non-obvious race condition or thread-safety issue.
For example:
public static class TenantListener extends SessionEventAdapter {
#Override
public void postAcquireClientSession(SessionEvent event) {
long tenantId = **business logic**;
event.getSession().setProperty("eclipselink.tenant-id", tenantId);
}
}
Using events is fine.
You could also inject the EntityManager and set the property, or inject the EntityManagerFactory and use joinTransaction() to join the active JTA transaction.

JPA: question about merging an entity before removing it

I know I have to merge the entity before removing it, but I never thought I have to do it inside EJB. First I have these:
e = (Event) scholarBean.merge(e);
scholarBean.remove(e);
in my managed bean. It give me this error
java.lang.IllegalArgumentException: Entity must be managed to call remove: com.scholar.entity.Event#998, try merging the detached and try the remove again.
So then I bring those two lines inside my session bean, and it works. Any idea why?
Managed Bean
myEJB.deleteEvent(e);
and
myEJB.java
public void deleteEvent(Event e){
e = (Event) merge(e);
em.remove(e);
}
I know I have to merge the entity before removing it
Not exactly. The object passed to remove has to be an entity and must not be detached. That's different.
but I never thought I have to do it inside EJB. First I have these (...)
Let's see what you're doing:
1: e = (Event) scholarBean.merge(e);
2: scholarBean.remove(e);
So in 1:, you call an EJB (very likely with a transaction-scoped Persistence Context) that merges the entity. But then the method ends, the transaction commits, the Persistence Context gets closed, making the returned entity detached again.
And in 2:, you pass the (still) detached entity to an EJB and tries to remove it, which is not allowed. And KaBOOM!
So then I bring those two lines inside my session bean, and it works. Any idea why?
It works because you're now working within the scope of the persistence context associated to the JTA transaction and you're thus really passing a managed entity to remove.
...and you can even combine those:
Like so:
public void deleteManCheck(ManCheck manCheck) {
em.remove(em.merge(manCheck));
}
I had the same transaction-issues when this was used in a servlet. When using the EJB-service-bean from a MDB it worked fine, since the transaction was started before the EJB was called, but when the EJB-call came from a servlet, there was no running transaction.
I solved this in my webapp by creating a filter that starts and commis a UserTransaction. Then every call to the EJB-methods joins my UserTransaction instead of starting it's own transaction.

Categories

Resources