Search code examples
jakarta-eeejbjava-ee-7apache-tomeetomee-7

Transactions inside tasks of ManagedScheduledExecutorService on TomEE 7.0.0?


Context

I want to schedule recurring background tasks using ManagedScheduledExecutorService. I get my Runnables/Callables via an Instance, so I have injection capabilities available inside my tasks.

My application runs on TomEE 7.0.0-SNAPSHOT webprofile.

Problem

As these tasks are accessing the database they need a transaction. However, inside the Runnable/Callable no transaction is active.

User transaction

The documentation for ManagedScheduledExecutorService states that

If a transaction is required, use a javax.transaction.UserTransaction instance. A UserTransaction instance is available (...) by requesting an injection of a UserTransaction object using the Resource annotation.

However, the injected

@Resource
private UserTransaction userTransaction;

is null when invoking the task.

Stateless bean

Another approach I took was to inject a stateless EJB into my task, hoping that this would create a transaction for me.

This resulted in the following exception on startup:

SEVERE: CDI Beans module deployment failed
java.lang.IllegalStateException: no interface to proxy for ejb StatelessEjb, is this is a MDB maybe you shouldn't use a scope?
    at org.apache.openejb.cdi.CdiEjbBean.createEjb(CdiEjbBean.java:252)
    at org.apache.openejb.cdi.CdiPlugin.getSessionBeanProxy(CdiPlugin.java:224)
    at org.apache.webbeans.container.BeanManagerImpl.getEjbOrJmsProxyReference(BeanManagerImpl.java:951)
    at org.apache.webbeans.container.BeanManagerImpl.getReference(BeanManagerImpl.java:777)
    at org.apache.webbeans.container.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:651)
    at org.apache.webbeans.inject.AbstractInjectable.inject(AbstractInjectable.java:111)
    at org.apache.webbeans.inject.InjectableConstructor.createParameters(InjectableConstructor.java:109)
    at org.apache.webbeans.inject.InjectableConstructor.doInjection(InjectableConstructor.java:72)
    at org.apache.webbeans.portable.InjectionTargetImpl.newInstance(InjectionTargetImpl.java:190)
    at org.apache.webbeans.portable.InjectionTargetImpl.produce(InjectionTargetImpl.java:173)
    at org.apache.webbeans.portable.AbstractProducer.produce(AbstractProducer.java:172)
    at org.apache.webbeans.component.AbstractOwbBean.create(AbstractOwbBean.java:127)
    at org.apache.webbeans.component.ManagedBean.create(ManagedBean.java:67)
    at org.apache.webbeans.context.DependentContext.getInstance(DependentContext.java:68)
    at org.apache.webbeans.context.AbstractContext.get(AbstractContext.java:124)
    at org.apache.webbeans.container.BeanManagerImpl.getReference(BeanManagerImpl.java:785)
    at org.apache.webbeans.inject.instance.InstanceImpl.create(InstanceImpl.java:306)
    at org.apache.webbeans.inject.instance.InstanceImpl.get(InstanceImpl.java:123)
(...)

Test case

I've created a small test case project on Github. It contains two branches, illustrating the problems mentioned above.

Questions

  • Shouldn't the @Stateless EJB work normally as all instances are obtained using injection?
  • Why does @Resource injection for the UserTransaction fail?

Solution

  • Using CDI to get it should fix it:

    @Inject
    private UserTransaction userTransaction;
    

    edit: the issue has been fixed for @Resource case: https://issues.apache.org/jira/browse/TOMEE-1672