On Jun 10, 2009, at 6:14 PM, Martin Probst wrote:
>> We do seem to be going around in circles a bit :-)
>
> Part of the reason for that is - I guess - that we both don't have an
> all that clear understanding of the problem nor the solution, so I
> think that's ok.
>
+ plus i think we are sort of discussing what possible conventions
would apply to signal a rollback or a commit.
>> I guess i am having a hard time understanding why in all cases the
>> commit or
>> rollback has to be performed after the response has been
>> serialized. And, as
>> you can tell i lack a certain experience in the area :-)
>
> Well, you just might need a transaction to write the response. For
> example, many O/R mappers support lazy loading, so if you access
> certain properties of your mapped objects during result serialization,
> you'll get errors if the transaction is already closed.
>
Ah, yes.
> In my use case, I'm writing code against our own native XML database
> (EMC xDB, formerly X-Hive/DB). When you serialize a large document or
> BLOB there, you certainly don't want to buffer it, commit, and then
> write the response but rather stream it out directly. Again, you'll
> need an open transaction for that.
>
OK.
> This of course might not apply for error cases where you probably
> don't need further access to the database (or do you? maybe for
> logging the error?).
>
>> So for that case the application could do one of the following:
>>
>> 1) return a 412, e.g. return Response.status(412).build().
>>
>> 2) throw a WebApplicationException(412)
>>
>> 3) or throw an exception that is mapped to 412.
>>
>> in addition to a general case of:
>>
>> 4) or thrown an exception that is unmapped and passed to the
>> container
>>
>> The common factor, for the first three, is you want on a 412 status
>> code to
>> perform rollback. In addition rollback should be performed for 4)
>> and for
>> the case of an exception thrown that is mapped to a 5xx response.
>
> See below.
>
>> I think you mentioned this before, but what if the application
>> could signal
>> that a set of status codes from a resource method should result in a
>> rollback ?
>
> I wouldn't really be happy with that. The meaning of a status code or
> how it happened is specific for a certain method, e.g. in method A if
> you end up with a 412 it means you need to roll back, but in method B
> in a larger application it might not mean the same.
It should be possible to declare per-method policy using an annotation.
> Again, status
> codes are part of the public interface of the RESTful service, but the
> internal implementation might be quite different - I think there is
> just no one-to-one mapping.
>
>>> You could either have
>>> a dedicated "ExceptionListener" or extend the ExceptionMapper
>>> somehow,
>>> but the first one is probably cleaner. Is there anything that speaks
>>> against this?
>>
>> I am still not sure that is sufficient for all the cases of how a
>> response
>> can be returned.
>>
>> However, do you propose that, given the pre-condition example above
>> that
>> cases 2, 3, 4 should result in rollback, but not 1)?
>
> I'd propose that we retain the semantics of contained managed
> transactions with servlets, so that if an unchecked exception is
> thrown (which somehow translates to an unexpected exception), a
> rollback should occur.
>
> I'd argue that the WebApplicationExceptions aren't really unexpected
> exceptions, as user code explicitly signals some condition with it -
> it's more like a special return value.
It can be used for that, but Jersey also uses it to internally to
produce 400, 404 and 500 responses. Also, if you are depending on some
third-party JAX-RS/Jersey code it might throw a
WebApplicationException as well.
It is really just a way to produce a response, just like mapping an
exception produces a response. In fact WebApplicationException can
also be mapped if so desired, otherwise it is sort of implicitly mapped.
> So in the place where the user
> code throws the exception, it can easily rollback or commit on it's
> own, or signal it to the container somehow. So here I would commit a
> transaction. So 1) and 2) should result in a commit.
>
> Just passing through the exception to the container (4) works as is.
> But that's a bit of a sad exception, as users will then just run into
> a standard Jetty, Tomcat, or whatever stack trace. It would be nice to
> be able to use an ExceptionMapper there.
>
Yes, you use a general catch all ExceptionMapper for those cases if
you wish.
> So I'd like to use an ExceptionMapper, and still be able to reliably
> do a rollback. The simple solution to that is just manually perform
> the rollback in the code for the ExceptionMapper, but this is easy to
> forget, and the code that initially opened the transaction is not
> involved in it.
>
>> I think we could have the following state on a response:
>>
>> a) for an exception mapped to a response we could set the response
>> state to
>> stay
>> MAPPED_EXCEPTION.
>>
>> b) for an umapped exception passed to the container, we could set
>> the
>> response state
>> to say UNMAPPED_EXCEPTION
>>
>> c) otherwise the state is DIRECT_RESPONSE
>>
>> Then in the Closeable the response state could be checked.
>>
>> Is that something that would work for you?
>
> Yes, that would work, at least if WebApplicationExceptions are a case
> for DIRECT_RESPONSE. Basically I need to know if execution flow went
> through one of the "catch (RuntimeException e)" blocks in
> WebApplicationImpl.
>
What we could do is store the exception instance in a property if it
was mapped (WebApplication exceptions are implicitly mapped if the
developer does not map them).
I would also like to try and support another state that declares that
the runtime threw a mapped exception. That way we can detect the case
of no resources matched, and thus for filters pass on to the next
filter in the chain.
> Somewhat related: there is no catch block around "response.write()" in
> that place. What happens if a streaming output throws a
> RuntimeException?
Or an IOException. The problem is that the response may have been
committed (bytes written out on the wire). In that case there is not
much that can be done, the server will probably close the connection
or prematurely end the response, so that the client detects an error,
but the server cannot communicate using HTTP what that error was.
Paul.
> The spec (1.1 draft) doesn't seem to cover that.
>
> Martin
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>