I have an EJB interceptor and I follow the BCE pattern suggested by Adam Bien, that is, all EJB calls on the boundary starts and finish a transaction which means there is no nested EJB calls (there might be nested CDI injected Bean calls though, but those should be inside the same transaction started at the ejb Boundary).
So in those ejb Boundaries I have an interceptor and I want to intercept or know if after the method call of the EJB the transacction commited already? (that is, if a EntityManager was involved that the COMMIT sql call was sent to the DB and returned succeesfuly)
NOTE: Of course, if I am the client of the EJB and I am calling the method, after the method call I know what happened with the transaction, but I am interested in intercepting that BEFORE the client receives the response from the EJB.
@AroundInvoke
public Object logMethodEntry(InvocationContext ctx) throws Exception {
Object proceed = null;
try {
proceed = ctx.proceed();
// is the transacction finished/commited already?
// is it still open ?
return proceed;
} catch (Exception e) {
throw e;
}
}
[UPDATE]: I accepted one good answer, but the thing is that THERE IS NO WAY in Java EE to receive an event of a transaction that HAS BEEN COMMITED. So regardless of the good answer, sadly there is no way to be notified in Java EE of a completed transaction, inside the server, of course, if you are the client caller, then you sure know the transaction commited or rolled back...
unless otherwise stated on the exception thrown, if an ejb method invocation throws an exception, it shall be rolled-back. Additionally, provided all calls to the DB were in the same transaction, they shall be deemed committed at the end of the transaction cycle.
In retrospect, all interceptors are invoked within the same transaction on which the ejb method it intercepts, was invoked (That's the reason the interceptor may decide in an event of an exception, to either roll-back or still commit the transaction).
Hence, you can know for sure, that the transaction completed successfully if within your interceptor call, after the proceed has been invoked and returned, there is no exception thrown, with a potential of transaction rollback.
So in your scenario:
@AroundInvoke
public Object logMethodEntry(InvocationContext ctx) throws Exception {
Object proceed = null;
try {
proceed = ctx.proceed();
// is the transacction finished/commited already?
// The transaction is successful, but afaik, it is not yet committed, until this method returns successfully
// is it still open ? More or less. You can still grab the Ejbtransaction and commit it manually or rollback if some other conditions have not been met yet
return proceed;
} catch (Exception e) {
//If this happens, and you propagate it, then for sure the transaction will be rolledback, and never get committed. Since all db calls were being done within this transaction, then no DB commit will be done.
throw e;
}
}
Edit: for you to actually commit the transaction in an interceptor, you will need to be running application-managed transaction, otherwise, it is prohibited by the EJB specs to call commit on a container managed transaction, you can of course call setOnrollback method of the EJBContext. Edit If you truly want to do some DB changes, i would recommend:
```
@Stateless
public class TransactionService {
@TransactionAttribute(REQUIRES_NEW)
public Object executeTransaction(final Callable<Object> task) {
return task.call();
}
}
@Interceptor
public class MyInterceptor {
@EJB
private TransactionService service;
@AroundInvoke
public Object logMethodEntry(InvocationContext ctx) throws Exception {
Object proceed = null;
try {
proceed = service.executeTransactional(()->ctx.proceed());
//If you reach here, you will be guaranteed of commit and then you can do the elastic search update
return proceed;
} catch (Exception e) {
//If this happens, and you propagate it, then for sure the transaction will be rolledback, and never get committed. Since all db calls were being done within this transaction, then no DB commit will be done.
throw e;
}
}
}