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
>>>>>
>>>>
>>>
>