users@jersey.java.net

[Jersey] Re: Handling Transactions

From: Ryan Stewart <rds6235_at_gmail.com>
Date: Wed, 23 Mar 2011 23:47:49 -0500

On Wed, Mar 23, 2011 at 7:36 PM, <charles_overbeck_at_yahoo.com> wrote:

> Hello,
>
> I want to begin a Hibernate transaction at the beginning of every
> request into my Jersey app, and commit or roll it back at the end. When
> there is an error, I want to return a response body with details about
> the error -- I have a JAXB bean that defines the error format.
>
> One way Hibernate recommends handling this scenario is by creating a
> Filter:
>
> http://community.jboss.org/wiki/OpenSessioninView
>
> The open session in view pattern isn't about beginning and ending
transactions. It deals with the problem of the hibernate session's already
being closed when the view needs to be rendered since the transaction
boundary is typically at the service layer. Without an open session,
lazy-loaded data can't be loaded into the object model.


> The problem with this approach is that if I get an error on the
> commit() or rollback(), it won't be super-easy for me to create the
> error body. Not impossible, but I won't be in Jersey then, so I won't
> be able to take advantage of the JAXB/MessageBodyWriters.
>
> So I found this thread that looks useful:
>
> http://markmail.org/thread/orcctyu7hczx3d5w#query:+page:1+mid:zczy5mguc
> n5qoolt+state:results<http://markmail.org/thread/orcctyu7hczx3d5w#query:+page:1+mid:zczy5mguc%0An5qoolt+state:results>
>
> I could basically move the code from the Hibernate filter from my first
> link, splitting it into a ContainerRequestFilter and a
> ContainerResponseFilter. But I have 3 questions that aren't 100% clear
> to me from that thread:
>
> 1) Paul says "if the resource throws an exception that is not mapped.
> The exception will get passed through to the container and response
> filters will not be called." If I have a @Provider that implements
> ExceptionMapper<Throwable>, I'm covered here, right?
>
> Yes, on an unmapped exception, the response filters don't get run. Creating
an ExceptionMapper<Throwable> would take care of that, I suppose, but that's
quite a lot like having a try { } catch (Throwable t) { } in your code,
which is pretty universally agreed to be a Bad Thing. At that point, I'd say
you're struggling against the framework and trying to hack your way into
making it work in a way it's not supposed to, and that never turns out well.


> 2) Paul also says "a filter declared before TransactionManagementFilter
> throws an exception. This breaks the filter chain". If I don't have any
> other filters, I don't have to worry about that. Well, I guess that
> answer is pretty obvious. But just checking.
>
> 3) I don't understand the need for CloseableService in Adam's sample
> code. Couldn't the ContainerResponse.filter() method also call
> Transaction.ensureTransactionClosed()? Just making sure it's not a
> different way of handling the closing the transaction, or if it is
> something really necessary that I'm missing. I haven't used Closeable.
> Is it for the case that something slips through 1 or 2, above? But
> haven't we ensured that nothing will slip through?
>
> As far as transactions go, perhaps so, but there's still the session to
consider. If you close the session in a ContainerResponseFilter, then it
will be closed when rendering the view, and you'll get
LazyInitializationExceptions if all the data isn't loaded. To close the
session at the correct time, you have to use the ClosableService.

I'm using Jersey 1.1.5.1. As in the above thread, I'm also not using
> Spring, and would prefer to keep it that way.
>
> Does anybody handle this this way, or maybe in a different way? Any
> thoughts?
>
> My only other thought is that either a Servlet Filter or a
ContainerRequestFilter is the wrong mechanism for transaction demarcation.
There are other, well-established solutions for that problem. Writing your
own transaction framework is a good way to rediscover the edge cases that
have already been accounted for in the established solutions. While you
don't want to use Spring, it has an excellent transaction framework and a
well-proven OpenSessionInViewFilter for handling the session lifecycle. In
addition, Jersey has very nice Spring integration. I'm sure others could
suggest other good options for transaction management.