users@javaee-spec.java.net

[javaee-spec users] [jsr342-experts] Re: Transactional interceptors and exceptions

From: Bill Shannon <bill.shannon_at_oracle.com>
Date: Mon, 30 Jan 2012 23:32:54 -0800

Did you see my other message from today? It addresses this issue.

Deepak Anupalli wrote on 01/30/2012 08:54 PM:
> May be a lame question, but can the transactional interceptor be applied to
> an EJB component as well?
>
> If so, are these exception handling rules going to be confusing when we have
> an EJB directly invoking another EJB (vs) EJB invoking another EJB through
> the interceptor?
>
> -Deepak
>
> -----Original Message-----
> From: David Blevins [mailto:david.blevins_at_gmail.com]
> Sent: 24 January 2012 03:30
> To: jsr342-experts_at_javaee-spec.java.net
> Subject: [jsr342-experts] Re: Transactional interceptors and exceptions
>
>
> On Jan 20, 2012, at 4:51 PM, David Blevins wrote:
>
>> I don't have a good vision for how separating them would be done, but I
> wonder if it's just as simple as having a "Transaction" interceptor and a
> "RollbackOnException" interceptor. Or some variation on the idea.
>
> This idea came to me as a self-documenting and very flexible possible
> approach:
>
> @Transactional
> @Rollback({RuntimeException.class, MyCustomException.class})
> public void doSomething() {
> //...
> }
>
> If the exception is assignable to anything in the list, the transaction is
> rolled back. At this point there isn't the need for @ApplicationException
> or anything similar. Just about anyone could look at that and know what's
> going on and how to alter the behavior.
>
> That's probably good enough right there.
>
> In the future if we get some generally applicable pattern for annotation
> reuse in place (e.g. meta-annotations, more generic version of stereotype,
> whatever want to call it), these common combinations can be easily reused:
>
> @Transactional
> @Rollback({RuntimeException.class, MyCustomException.class})
> @RolesAllowed({"Manager", "Admin"})
> @Metatype
> @Target(ElementType.TYPE)
> @Retention(RetentionPolicy.RUNTIME)
> public @interface AcmeTransactionalOperation {
> }
>
> Then..
>
> @AcmeTransactionalOperation
> public void doSomething() {
> //...
> }
>
> Effectively, the problem of what we need to squish together for convenience
> isn't our problem anymore. We just focus on clear and separate concerns.
> With some ability to compose things together, the question of "will users
> also want x with y" where the answer is clearly "sometimes" becomes an easy
> one for users to solve for themselves.
>
> At that point we as spec designers need to only ask "will users want x and
> possibly not y". And of course, there'd be some flexibility to get that
> answer wrong. If we learn annotation X encompasses too much functionality
> (the "i got more than I wanted" problem), we could of course split those
> concerns into annotations D and E then redefine X as a meta-annotation
> comprised of D and E.
>
>
> -David
>
>
>> I can see concrete use cases for people wanting the protection of
> MANDATORY and having the mindset of, "Look, it's your transaction, deal with
> the exceptions as you see fit. Don't make me tell you what's safe and
> isn't."
>>
>> Of course the concept of app/system exceptions could still be supported
> for when people opt-into the "RollbackOnException" contract, though I wonder
> if it would be all that used. Theoretically, if you had specific goals for
> your exception handling, you could simply assume that responsibility. Don't
> use the standard "RollbackOnException" interceptor and instead write your
> own interceptor to call setRollbackOnly() using whatever conditions you
> wanted. With things separated, you'd have this ability, with them "smushed"
> together you'd have to write all your own transaction handling code.
>>
>> A lot of things can simply be traced back to the fact that interceptors
> did not exist when these particular APIs were created.
>>
>> For as large as the CMT API is it's actually not that complete. For
> example, why not an interceptor that calls getRollbackOnly() and throws a
> "DontBotherInvokingMeException" if the answer is false? Was probably not
> worth the xml before and perhaps not worth annotation now, but it's an
> interesting omission.
>>
>>> I definitely agree with you about the SFSB destruction issue flagged
>>> in your blog. I would advocate that we try to fix that for the
>>> transactional interceptor case. We could try to fix it in general
>>> with the introduction of more metadata, if the EJB EG wants.
>>
>> Will definitely give that some thought.
>>
>>>
>>>>
>>>> Not a proposal, but some thoughts.
>>>>
>>>
>>> thanks again for posting
>>
>> Thanks for tackling this topic. It's a fun one. We could certainly
>> green-light the CMT API as-as with no harm, but there's no denying we
>> won't get this chance again for quite a long time :)
>>
>>
>> -David
>>
>>>>>
>>>>> Jan 18, 2012 07:53:44 PM, jsr342-experts_at_javaee-spec.java.net wrote:
>>>>> Supporting a superset of Spring and EJB would result in something
>>>>> very complex. In particular, the way Spring allows control over the
>>>>> rollback behavior using include lists and exclude lists and class
>>>>> names and Class objects is very complex. We were hoping to satisfy
>>>>> most developers with something much simpler than Spring or EJB.
>>>>>
>>>>> Which of the features from Spring's @Transactional annotation do
>>>>> you think are the most used?
>>>>>
>>>>> reza_rahman_at_lycos.com wrote on 01/17/12 09:47:
>>>>>> Sorry for the delay in responding. Things are hectic these days...
>>>>>>
>>>>>> I actually think EJB 3 application vs. system exception is a good
>>>>>> idea (except for that I don't think the special treatment of
>>>>>> RemoteException is really needed
>>>>>> -- in Spring, system exception == runtime exception). It's easy to
>>>>>> explain, works in the real world and corresponds nicely with
>>>>>> exception handling best
>>>>>> practices:
> http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?page=1.
>>>>>> Now, I do think it would be very useful to provide a mechanism to
>>>>>> override default exception level behavior (no
>>>>>> annotation/checked/unchecked/_at_ApplicationException) per
>>>>>> bean/method. Basically, I would like to see the super-set of
>>>>>> Spring
>>>>>> (http://static.springsource.org/spring/docs/2.0.x/api/org/springfr
>>>>>> amework/transaction/annotation/Transactional.html)
>>>>>> and EJB exception handling.
>>>>>>
>>>>>> As to wrapping exceptions, I do agree it's completely overkill and
>>>>>> counter-intuitive (Spring does not do it, for example).
>>>>>>
>>>>>> Hope it helps.
>>>>>>
>>>>>> Jan 10, 2012 03:14:50 PM, jsr342-experts_at_javaee-spec.java.net
>>>>>> <mailto:jsr342-experts_at_javaee-spec.java.net> wrote:
>>>>>>
>>>>>>
>>>>>> It looks like we're in general agreement on the transactional
>>>>>> interceptor approach I proposed earlier.
>>>>>>
>>>>>> Aside from the more obvious open issues around naming, there is an
>>>>>> issue related to the handling of exceptions that we need to resolve.
>>>>>>
>>>>>> The issue relates to what should happen with regard to the state
>>>>>> of a transaction when an exception is thrown that reaches a
>>>>>> transactional interceptor.
>>>>>>
>>>>>>
>>>>>> First, some background on how EJB handles container-managed
> transactions....
>>>>>>
>>>>>> The EJB spec distinguishes between "system exceptions", which
>>>>>> cause the container to mark the transaction for rollback, and
>>>>>> "application exceptions", which by default do not cause the
>>>>>> transaction to be marked for rollback.
>>>>>>
>>>>>> An application exception is either a checked exception (other than
>>>>>> the
>>>>>> RemoteException) or a runtime exception annotated with
> @ApplicationException.
>>>>>>
>>>>>> @Target(TYPE) @Retention(RUNTIME)
>>>>>> public @interface ApplicationException {
>>>>>>
>>>>>> /**
>>>>>> * Indicates whether the container should cause the transaction to
>>>>>> * rollback when the exception is thrown.
>>>>>> */
>>>>>> boolean rollback() default false;
>>>>>>
>>>>>> /**
>>>>>> * Indicates whether the application exception designation should
>>>>>> * apply to subclasses of the annotated exception class.
>>>>>> */
>>>>>> boolean inherited() default true;
>>>>>> }
>>>>>>
>>>>>>
>>>>>> An EJB system exception is a subclass of RemoteException or a
>>>>>> subclass of RuntimeException that has not been designated as an
>>>>>> application exception.
>>>>>>
>>>>>> When the EJB container intercepts a system exception (at a
>>>>>> business method boundary), it causes the current transaction to be
>>>>>> marked for rollback. When the called method runs in the context of
>>>>>> the caller's transaction, the container throws the
>>>>>> EJBTransactionRolledBackException (or some variant thereof). If a
>>>>>> new transaction was *started* for the called method, the container
>>>>>> throws the EJBException. In both these cases, the original
>>>>>> exception is wrappered. Application exceptions are thrown back to the
> caller as is.
>>>>>>
>>>>>> If the caller receives an application exception, the caller
>>>>>> presumably knows based on the exception type whether the exception
>>>>>> causes rollback or not. Unless the caller is familiar with the
>>>>>> transaction attribute of the called method, however, the caller
>>>>>> doesn't know whether its own transaction was marked for rollback
>>>>>> or whether only the callee's transaction was rolled back. However,
>>>>>> the caller can invoke the getRollbackOnly method to determine the
>>>>>> state of its own transaction.
>>>>>>
>>>>>> In the case of a system exception, if the caller receives the
>>>>>> EJBException, the caller can assume that the callee's transaction
>>>>>> was rolled back, but that the caller's own transaction was not
> affected.
>>>>>> If the caller receives the EJBTransactionRolledBackException, the
>>>>>> caller knows that its own transaction was marked for rollback (and
>>>>>> that the callee was run within the context of that same transaction).
>>>>>>
>>>>>>
>>>>>> So much for background.... Now, what should the behavior be for
>>>>>> transactional interceptors?
>>>>>>
>>>>>> While we could adopt the EJB approach (modulo some renaming), Bill
>>>>>> and I are concerned that it is too complex. (See Chapter 14
>>>>>> ("Exception
>>>>>> Handling") of the EJB 3.1 spec for the gory details.)
>>>>>>
>>>>>> We propose a simpler approach along the following lines:
>>>>>>
>>>>>> By default, all exceptions should result in the current
>>>>>> transaction being marked for rollback. If the developer believes
>>>>>> that the exception should not cause rollback, he or she annotates
>>>>>> the exception class with @DontRollbackTransaction (real name for this
> exception *TBD*).
>>>>>>
>>>>>> The DontRollbackTransaction annotation is simply:
>>>>>>
>>>>>> @Target(TYPE)
>>>>>> @Retention(RUNTIME)
>>>>>> @Inherited
>>>>>> public @interface DontRollbackTransaction {}
>>>>>>
>>>>>> All exceptions are thrown back without any wrappering. While we
>>>>>> can understand the rationale for wrappering an exception that
>>>>>> marks the caller's transaction for rollback in a
>>>>>> TransactionRolledbackException, we're not convinced that this is
>>>>>> needed. Likewise, we're not convinced of the need to make a
>>>>>> distinction by means of exception wrappering as to whether the
> callee's transaction was rolled back.
>>>>>>
>>>>>>
>>>>>> We'd like your feedback on this and on your experience with regard
>>>>>> to how developers are actually making use of the current EJB
>>>>>> facility, particularly in view of the assumptions that we are making.
>>>>>>
>>>>>> Again, we are assuming the following:
>>>>>>
>>>>>> (1) It is not essential that the caller be able to identify from
>>>>>> an exception that it receives whether its own transaction was
>>>>>> marked for rollback, as the caller can use the getRollbackOnly
>>>>>> method to determine this.
>>>>>>
>>>>>> (2) It is not essential that the caller be able to identify by
>>>>>> means of the exception that it receives back whether a transaction
>>>>>> was started on behalf of a method that it invoked, as it can use
>>>>>> its knowledge of the exception received and getRollbackOnly status
>>>>>> to determine this if it does not already know this information.
>>>>>>
>>>>>> (3) Subclasses of dont-rollback exceptions will typically be
>>>>>> dont-rollback exceptions, and, if not, they can be defined to not
>>>>>> extend dont-rollback exceptions. (Note that if we receive
>>>>>> compelling feedback from developers to the contrary on this point,
>>>>>> we could always add a an element to the annotation to control this
>>>>>> at a later time. If we think this is at all likely, we should
>>>>>> choose an annotation name accordingly.)
>>>>>>
>>>>>>
>>>>>> Please post your feedback.
>>>>>>
>>>>>> Other specleads should feel free to forward this message to your
>>>>>> expert groups for further input.
>>>>>>
>>>>>>
>>>>>> thanks,
>>>>>>
>>>>>> -Linda
>>>>>>
>>>>>
>>>>
>>
>