users@javaee-spec.java.net

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

From: Deepak Anupalli <deepak_at_pramati.com>
Date: Tue, 31 Jan 2012 13:39:43 +0530

Bill, I happened to send this mail yesterday but it failed, so I resent it
in the morning without reading the other mails. Yes, it addresses all the
concerns I had in the context of EJBs.

-Deepak

-----Original Message-----
From: Bill Shannon [mailto:bill.shannon_at_oracle.com]
Sent: 31 January 2012 13:03
To: jsr342-experts_at_javaee-spec.java.net
Subject: [jsr342-experts] Re: Transactional interceptors and exceptions

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/springf
>>>>>> r
>>>>>> 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
>>>>>>
>>>>>
>>>>
>>
>