deltaspike-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David Smalley <smalley.thed...@gmail.com>
Subject UserTransactionResolver in Tomcat
Date Wed, 02 Sep 2015 21:54:30 GMT
Hello,

I am using the Deltaspike JPA module + WELD in a web app targeting Tomcat
(8). I have set up Atomikos Transaction Essentials to provide JTA
transactions, and all of that is working fine. I want to use Deltaspike for
the @Transactional and @TransactionScoped annotations. After enabling the
BeanManagedTransactionStrategy, I received NameNotFound exceptions for
TransactionSynchronizationRegistry. Some quick research showed that
Atomikos implements JTA 1.0 which doesn't include the registry, and
initially I thought this was the problem, but actually, it isn't.

UserTransactionResolver declares a field @Resource UserTransaction
userTransaction. The code seems to assume the only thing which can go wrong
with this is that injection fails and it might be null, but actually, in
Tomcat, it throws a NameNotFound JNDI exception when it is dynamically
instantiated in resolveUserTransaction(), and so its alternative lookup
logic is never called. resolveUserTransaction() catches this exception and
always returns null, which is interpreted as there being an active CMT,
which causes the lookup for the none-existent registry, but that is already
wrong...there is no EJB and thus no CMT in a plain Tomcat environment.

I have been able to make this work by changing the code in one of two ways:
either change the annotation to @Resource(mappedName =
"java:comp/UserTransaction") which causes the injection to succeed, or
remove it entirely, in which case the field is null, and the alternative
lookup logic is (successfully) invoked.

After either of these changes, the BeanManagedUserTransactionStrategy works
correctly, and I have declarative JTA transactions with plain Tomcat +
Atomikos + Eclipselink. However, I don't want to build my own version of
Deltaspike for deployment.

I have worked around this problem by providing my own transaction strategy
which extends BeanManagedUserTransactionStrategy and overrides
resolveUserTransaction() like this:

public UserTransaction resolveUserTransaction() {

    UserTransaction userTransaction = super().resolveUserTransaction();

    if (userTransaction == null) {
        userTransaction = JNDIUtils.lookup("java:comp/UserTransaction",
UserTransaction.class);
    }

    return userTransaction;
}

It works, but it feels like a kludge. For what it is worth, the spec
recommends against assigning to injected fields, probably because you
usually get a proxy rather than a plain object. I think the use of
@Resource in UserTransactionResolver is dangerous, since it can throw an
exception during instantiation, which means handling the failure must
happen in the calling code. Because it is dynamically created in
resolveUserTransaction(), this is possible, but if you had injected it
directly into the strategy there would be no workaround other than copying,
modifying, and renaming the source.

BTW, when I first found this, I tried to find a way to coerce the plain
@Resource annotation into working, either by mapping in web.xml, or trying
to provide my own implementation of WELD's ResourceInjectionServices spi,
but so far, I haven't been able to make it work. WELD's documentation on
replacing that spi seems to be incorrect, though that's not your problem.

I suppose my question is: is there some way in Deltaspike to cause the
@Resource annotation to have the mappedName attribute dynamically added? I
have already determined that the ProcessInjectionPoint event is never fired
for @Resource fields (I tried to handle them in an extension); they are
deferred to the WELD service, which I have been unable to customize.

Dave

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message