-
1. Re: Exceptions and transaction rollback
jaikiran Feb 20, 2013 12:20 AM (in response to cfillot)Is this what you are after:
public class MyEJBA { @Resource private EJBContext ejbContext; public void myMethodOnEJBA() { .... MyEJBB bBean = getBBean(); try { bBean.doSomething(); } catch (MyAppException expected) { ... // do whatever } // do some other things if (shouldIThrowMyAppExceptionAndRollbackTx()) { // mark tx for rollback ejbContext.setRollbackOnly(); // throw our app exception throw new MyAppException(); } } ... }
-
2. Re: Exceptions and transaction rollback
cfillot Feb 20, 2013 2:37 AM (in response to jaikiran)Hi Jaikiran,
Thanks for taking a look at my problem. My example was incorrect, in fact this is the method in EJB "B" that can be called either from another EJB ("A") in
my example, or directly from the web layer (servlet). So this method can throw an AppException, but I would like that the rollback happens only when this
method is called directly from the web layer, but not when EJB "A" calls it. If I put @ApplicationException(rollback=true), the rollback will happen in both
situations. Of course I give the example for 2 EJBs and 1 method, but the real application is more complex and I would like to have a generic method to do
that.
First I thought writing an interceptor, but I don't think I can determine if the method invocation is from another EJB or from the web layer (otherwise I would
have been able to catch the exception, and if the call was from the web layer, calling ejbContext.setRollbackOnly() would have done the job).
-
3. Re: Exceptions and transaction rollback
cfillot Feb 20, 2013 1:07 PM (in response to cfillot)I thought to this solution, based on an Interceptor and ThreadLocal variable.
public class EJBBoundaryMark { private static ThreadLocal<Boolean> mark = new ThreadLocal<Boolean>(); public static ThreadLocal<Boolean> getMark() { if (mark.get() == null) mark.set(true); return mark; } public static void setMark(boolean m) { mark.set(m); } public static void destroy() { mark.remove(); } } import javax.annotation.Resource; import javax.ejb.EJBContext; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class EJBBoundaryInterceptor { @Resource private EJBContext ejbContext; @AroundInvoke public Object intercept(InvocationContext ctx) throws Exception { Boolean mark = EJBBoundaryMark.getMark().get(); EJBBoundaryMark.setMark(false); try { return ctx.proceed(); } catch(Exception e) { if (mark == true) ejbContext.setRollbackOnly(); throw e; } finally { if (mark == true) EJBBoundaryMark.destroy(); } } }
Is it something totally dangerous/stupid/... ?
-
4. Re: Exceptions and transaction rollback
sfcoy Feb 21, 2013 4:30 AM (in response to cfillot)If you're using default CMT, then EJB A and EJB B will be particpating in the same transaction. So if you catch the exception before it crosses the transaction boundary it will not be rolled back.
To rollback the transaction after catching the checked exception, just wrap the checked exception in an EJBException and throw that.
You really don't want to make this stuff more complicated than it needs to be as presumably it's a rare event.
-
5. Re: Exceptions and transaction rollback
cfillot Feb 21, 2013 4:55 AM (in response to sfcoy)If you're using default CMT, then EJB A and EJB B will be particpating in the same transaction. So if you catch the exception before it crosses the transaction boundary it will not be rolled back.
Just to see if I understand correctly:
- If the exception is a checked exception without @ApplicationException annotation, and crosses the transaction boundary, there is no rollback at all.
- If the exception is a checked exception with @ApplicationException(rollback=true), with the following situation: servlet -> EJB A -> EJB B,
the exception being thrown by B but catch by A (so the exception does not cross the transaction boundary), the transaction will be put in rollback.
My problem is that the @ApplicationException(rollback=true) put the transaction in rollback as soon as an EJB throws the exception, whereas
I would like the rollback occur only if the exception crosses the transaction boundary.
-
6. Re: Exceptions and transaction rollback
sfcoy Feb 21, 2013 6:22 AM (in response to cfillot)1 of 1 people found this helpfulI think your summary is correct.
Basically, you're asking for the same method to behave differently, depending upon where it's called from.
It seems like you need two different methods to me. Perhaps using a delegate method like:
{code:java}
@ApplicationException(rollback=true, inherited=false)
public MyApplicationException extends Exception {
...
}
public MyRollbackFreeApplicationException extends MyApplicationException{
...
}
@Stateless
public class MyEJBA {
public void someOperation() throws MyApplicationException {
...
// oops
throw new MyApplicationException();
}
public void someRollbackFreeOperation() throws MyApplicationException {
try {
someOperation();
} catch (MyApplicationException e) {
throw new MyRollbackFreeApplicationException(e);
}
}
}
@Stateless
public class MyEJBB {
@EJB
private MyEJBA myEJBA;
public void someOtherOperation() {
try {
myEJBA.someRollbackFreeOperation();
} catch (MyApplicationException e) {
// do recovery stuff
}
}
}
{code}
-
7. Re: Exceptions and transaction rollback
cfillot Feb 22, 2013 3:15 AM (in response to sfcoy)Thanks Stephen, I think your suggestion should work fine!