Execute manual Rollback in JTA environment in Stateless EJB - java

I develope a registration function. A new user account will be created in the database, and after that a welcome email will be sent. The email sending function can execute a exeption. If a exception will be thrown the created user account has to be deleted. The problems is that my stateless bean rollbacks only if an unchecked exception will be thrown. My exception is a checked exception. Either I have to wrap in a unchecked exception, then I cant response with a proper http status code (using jax rs) or I have to execute a manual rollback.
Can someone help and offer a better solution for my scenario?
Thanks!

You can annotate your checked exception with the annotation: #ApplicationException(rollback = true).
e.g.:
#ApplicationException(rollback = true)
public class MyApplicationException extends Exception{
}
This will mark the current transaction for rollback.
Edit:
I do not want to use a exception to execute a rollback because I cant response with a http status code
Other alternative is to explicitly marks the transaction for rollback using the SessionContext.setRollbackOnly() method. I don't know your app design, but an example would be:
#Stateless
public class MyBean(){
#Resource
private SessionContext ctx;
public void doSomething() {
try {
//code that sends a mail
} catch (Exception e) {
ctx.setRollbackOnly(); //the transaction will not commit
//log exception
}
}
}

Related

Intercepting #Transactional After Optimistic Lock for Asynchronous Calls in Restful App

The question I have today is how to retry a method after the #Transactional annotation causes an Optimistic Lock Exception (OLE) and rolls back the transaction.
I have asynchronous calls to a Restful application that are attempting to update a database object based on some business logic. If I get an OLE, I'd like to retry the transaction after a delay of 0.2-0.5 seconds.
#Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED, readOnly = false)
public Response myMethod(Long myParam) throws Exception {
~Call to update db using hibernate after business logic~;
return Response.ok().build();
}
I've tried using AspectJ to intercept my method after it throws the OLE so that I can retry. However, the issue is the #Transactional annotation. My method is not throwing the error message since business logic is not failing. Instead, myMethod returns a 200 response, but the OLE exception is encountered and then thrown in the ResourceJavaMethodDispatcher.java class that is responsible for invoking myMethod.
My aspect class:
#Aspect
public class myAspect {
#AfterThrowing(value = "execution(* com.package.blah.myClass.myMethod(..)) && args(.., myParam)", throwing = "ex")
public Response catchAndRetry(JoinPoint jp, Throwable ex, Long myParam) throws Throwable {
Response response = null;
response = invokeAndRetry(jp, myParam);
return response;
}
}
The invokeAndRetry() method has the logic to call wait on the thread and then retry up to a maximum of three tries.
I can successfully get into myAspect from an exception thrown by business logic; but the OLE thrown from the transaction does not get caught in myAspect.
Having said all of that, is there a way to wrap/encapsulate/intercept the #Transaction annotation in order to run my retry logic?
Side notes:
1) I've looked into creating my own #Retry annotation based on the example here. I've used that dependency to try his #Retry annotation, but to no avail.
2) I'll be looking into Spring's #within to see if that could prove useful.
The short answer is: you shouldn't try to reuse an EntityManager after an exception occurs. According to the Hibernate EntityManager User guide on Transactions and concurrency, which most probably applies to all JPA providers:
If the EntityManager throws an exception (including any SQLException), you should immediately rollback the database transaction, call EntityManager.close() (if createEntityManager() has been called) and discard the EntityManager instance. Certain methods of EntityManager will not leave the persistence context in a consistent state. No exception thrown by an entity manager can be treated as recoverable. Ensure that the EntityManager will be closed by calling close() in a finally block. Note that a container managed entity manager will do that for you. You just have to let the RuntimeException propagate up to the container.
You might be able to do the retry the operation in a new transaction with a new instance of an EntityManager though, but that's a different use-case.
After doing some research and looking at some more tutorials, I found a way to have my aspect take precedence over #Transactional. Just below the #Aspect tag, I added the annotation #Order(1).
This gives my aspect higher priority since #Transactional is defaulted to Ordered.LOWEST_PRECEDENCE. See Spring documentation for some more details about #Order.

Why is java ws rs ExceptionMapper is picking non application exceptions also?

I have a web application in which I throw some custom exceptions(application exceptions annotated with #ApplicationException) and there is an exception mapper(provider annotated with #Provider) for each. Recently I forgot to annotate an exception with #ApplicationException and still the mapper is able to identify the exception and format the response properly.
Then I checked the documentation and I understood that the annotation will be inherited by its child class by default. So I removed the annotation from the super class and checked. The mapper still identified the exception and formatted the response.
Then I went even forward and tried throwing java.lang.IllegalArgumentException and wrote a mapper class for it. It also worked properly. Is javax.ws.rs.ext.ExceptionMapper independent of the exception being thrown. Will it not check if whether thrown exception is really annotated with #ApplicationException?
#Provider
public class IllegalArgumentExceptionMapper implements ExceptionMapper<java.lang.IllegalArgumentException> {
#Override
public Response toResponse(java.lang.IllegalArgumentException exception) {
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Somewhere in my service class:
throw new java.lang.IllegalArgumentException("Problem with the payload. Please check the payload you are sending");
The answer is no, it will not check if whether thrown exception is really annotated with #ApplicationException.
The exception mapper is independent of the #ApplicationException.
All the exception mapper knows is, if there's no exception caught until the almost last layer, it will be processed here, if it find a matching provider.
You can also actually create a provider for RuntimeException and all exception happened in the REST request will land here (but this is not good practice, we should always throw custom exception and catch them with the provider and convert them to good error response).
When you annotate the exception with #ApplicationException you can control things like whether the transaction should be rollback, and whether it will be wrapped by EJBException etc etc.

How to catch OptimisticLockException in JPA

I've read out a couple of questions here regarding the OptimisticLockException with JPA, used in an stateless session bean. It is thrown, but not where I expect it obviously.
Here is the code where I expect to get the exception:
try
{
productFacade.edit(product);
}
catch(Exception {
return "lock";
}
The productFacade is generated with NetBeans and it is an EJB with a local interface, an it implements an AbstractFacade abstract class. As far as I read, this has something to do with transactions in JPA. Because the exception is thrown after the method this code snippet is in is left, not after edit() is called. Where should I than handle the exception?
Also, I will be needing the transaction mechanism for later, because I will need to update multiple products (or none if some is locked). I've found some code examples, but this leaves me wondering how should I work with transactions?
The lock error will not be thrown until the transaction commits. So you would need to handle it outside of your SessionBean or use a container managed transaction.
Or, you could just call flush() on your JPA EntityManager, then the error will be thrown.
use save and flash and catch with Exception
try {
log.info("save data versions: " + employee.getVersion());
someRepository.saveAndFlush(employee);
} catch (Exception ex) {
log.info("catch Exception");
throw new OptimisticLockException("retry data Exception");
}
if want to use retry can add anotation #Retryable with some flagging

Force Hibernate To Save A Specific POJO

I have some code calling a webservice and it returns an ID. I am saving this ID in the database using hibernate. I have a filter that opens the session and commits it, rolling back when any exception occurs within the contained code. Since there is no way to get back the ID returned by the webservice I would like to save this in the database EVEN if there is an exception that occurred later on in the code. Is there anyway to do this using the same session?
It depends on who throws the exception. If it is thrown by the hibernate session object you cannot reuse the session anymore as stated in hibernate Session documentation:
If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs.
If the exception is thrown by some other code, then yes, you can do something like this:
Long yourIdFromWebservice = ...
try {
// do some processing that might result in an exception
}
catch(//the interesting exception, but not HibernateException) {
//maybe log it, rethrow it
}
finally {
session.save() //save what needed to be saved
}
or depending on your use case:
try {
// do some processing that might result in an exception
session.save() //save all stuff if no exception
}
catch(//the interesting exception, but not HibernateException) {
session.save() //save only the id from the webservice
}
The right way to do that is to use two transactions: one to save the ID, and one to save the rest of your work.
If you're using EJB, you could do the save of the ID in a bean of its own, and annotate it with a TransactionAttribute of REQUIRES_NEW.
Otherwise, you can look at what control over transactions your environment gives you, and figure out a way to have two of them.

EJB3 - handling RollBackExceptions

I have an EJB3 application which consists of some EJB's for accessing a DB, and exposed via a Session Bean as a web service.
Now there are two things I need to find out:
1) Is there any way I can stop SQL exceptions from causing the web service from throwing a SOAP Fault? The transactions are handled by the container, and currently sql exceptions cause a RollBackException to be thrown, and consequently the transaction to be rolled back (desired behaviour) and the web service to throw a fault (not desired).
2) I wish to extend the webservice to be able to take in a list of entities, and the session bean to persist each. However, I want each entity to be executed in its own transaction, so that if one fails the others are not affected (and again the web service should not fault).
For (1) I have tried to catch the RollBackException, but I assume this is thrown somewhere on another thread, as the catch block is never reached. I assume for (2) I will need to look into User Transactions, but firstly would prefer the container to manage this, and secondly do not know how to force the use of user transactions.
Thanks.
no, you can do all this with container managed transactions (and this is definitely preferable, as managing transactions is a pain).
the gist of the solution is to create a second EJB with a local interface only and the transaction semantics you desire. then your "public" ejb, which the web-service is calling directly, calls into this second ejb via its local interface to do the actual work.
something along the lines of:
public class MyPublicEjb {
#EJB
private MyPrivateImpl impl;
public void doSomething() {
try {
impl.doSomething();
} catch(TXRolledBack) {
// handle rollback ...
}
}
}
I know this looks sort of ugly, but trust me, this is far preferable to directly manipulating transactions.
For (1): Debug your code to find out where the exception is being thrown and what is causing it. Then handle the exception there.
For (2): Wrap each instance with beginTransaction() and commit().
for(each Entity){
try{
//begin transaction
//save entity
//commit
} catch(Exception e) {
//handle Exception, but continue on
}
}

Categories