1
votes

Is it possible to catch an exception in a CMT(Container Managed Transaction) stateless bean?

The code below wont catch any exeption when I tried it. If I use BMT(Bean Managed Transaction), I can catch the exception. But I want to remain with CMT.

@Path("books")
public class BookResource 
{

    @EJB
    private BooksFacade book_facade;

    private Books local_book;


    @POST
    @Consumes({"application/xml", "application/json"})
    public Response create(Books entity) 
    {
       try 
        {
            book_facade.create(entity);
        } catch (RuntimeException ex) 
        {
            System.out.println("Caught database exception");
        }
       return Response.status(Response.Status.CREATED).build();
    }



 public class TXCatcher
{

    //@Resource
    //UserTransaction tx;
    private final static Logger LOG = Logger.getLogger(TXCatcher.class.getName());

    @AroundInvoke
    public Object beginAndCommit(InvocationContext ic) throws Exception 
    {
        //ic.proceed();
        System.out.println("Invoking method: " + ic.getMethod());
        try 
        {
            //tx.begin();
            Object retVal = ic.proceed();
            //tx.commit();
            return retVal;
        }catch (RollbackException e) 
        {
            LOG.log(Level.SEVERE, "-----------------Caught roolback(in interceptor): {0}", e.getCause());
            System.out.println("Invoking method: " + ic.getMethod());
            throw new CustomEx("Database error");
        }catch (RuntimeException e) 
        {
            LOG.log(Level.SEVERE, "-----------------Caught runtime (in interceptor): {0}", e.getCause());
            System.out.println("Invoking method: " + ic.getMethod());
            //tx.rollback();

            throw new CustomEx("Database error",e.getCause());
            //throw new CustomEx("Database error");
        }



        //return ic.proceed();


    }

}

2

2 Answers

0
votes

It depends what kind of problem you're trying to catch. You could try an explicit EntiyManager.flush, but depending on your data source isolation level, some errors cannot be caught until transaction commit, and there is no mechanism for catching transaction commit errors for a CMT. If that's the case, your only option is to use BMT (even though you said you don't want to). The only suggestion that might make that more palatable would be to write an EJB interceptor that behaves similarly to CMT (that is, inject UserTransaction into the interceptor, and begin/commit/rollback in the @AroundInvoke).

0
votes

By placing the following above my function in my BooksFacade class create function, the CMT created a 2nd transaction within the first transaction. When the exception was thrown from the 2nd transaction, my BookResource class create method could catch it. No need for BMT.

@Overide
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void create(Books entity) 
{
    super.create(entity);
}  

I noted that the annotation only works when placed on the individual methods, by placing it on the class itself wont make a difference.