Hey guys,

Here's something I should know about Java EE (Since I've put on training
classes :D) but I don't.

So we have some batch processes that need to run, but only one instance of
the app in the cluster needs to run them. We're trying to implement a
cluster-wide lock via a database via a "database locks" table. So when a
timer expires, first node to insert the row in the database wins the lock.

We have the business logic in an ApplicationScoped CDI bean marked with
@Transactional(Required). It starts doing some work, then at some point it's
going to need to acquire the cluster-wide lock. I created a Singleton EJB
with @TransactionMangement(Bean) where it does utx.begin, insert row, then
utx.commit(). See code below.

The problem is I'm getting a `Can't use UserTransaction from @Transaction
call` message from TomEE. I tried wrapping my bean managed ejb
[InternalLockBean in the stack trace below] in another EJB that has
@TransactionAttribute(NOT_SUPPORTED) [DatabaseLockService in the stack trace
below], but got the same result, which really surprised me.


Mar 27, 2019 10:33:19 AM
org.apache.openejb.core.transaction.EjbTransactionUtil handleSystemException
SEVERE: EjbTransactionUtil.handleSystemException: The bean encountered a
non-application exception; nested exception is: 
        java.lang.RuntimeException: java.lang.IllegalStateException: Can't use
UserTransaction from @Transaction call
javax.ejb.EJBException: The bean encountered a non-application exception;
nested exception is: 
        java.lang.RuntimeException: java.lang.IllegalStateException: Can't use
UserTransaction from @Transaction call
        at
org.apache.openejb.core.ivm.BaseEjbProxyHandler.convertException(BaseEjbProxyHandler.java:447)
        at
org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:351)
        at
com.xxx.service.InternalLockBean$$LocalBeanProxy.acquireLock(com/xxx/service/InternalLockBean.java)
        at
com.xxx.service.DatabaseLockService.acquireLock(DatabaseLockService.java:22)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        
@Singleton
@Lock(LockType.READ)
@TransactionManagement(TransactionManagementType.BEAN)
public class InternalLockBean {
        @Resource
        private UserTransaction utx;
        @Resource
        private UserTransaction utx;

        public boolean acquireLock(String lockName) {
                if (lockName == null) {
                        throw new IllegalArgumentException("lockName cannot be 
null");
                } else {
                        lockName = StringUtils.truncate(lockName, 
MAX_LOCK_LENGTH);
                        try {
                                utx.begin();
                                DatabaseLock lock = new DatabaseLock(lockName, 
lockOwner);
                                em.persist(lock);
                                try {
                                        utx.commit();
                                } catch (Exception e) {
                                        log.trace("acquireLock() failure on 
commit, returning false", e);
                                        return false;
                                }
                                return true;
                        } catch (Exception e) {
                                throw new RuntimeException(e);
                        }
                }
        }
}

@Singleton
@Lock(LockType.WRITE)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class DatabaseLockService {
        @EJB
        private InternalLockBean internalBean;

        public boolean acquireLock(String lockName) {
                return internalBean.acquireLock(lockName);
        }
}



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html

Reply via email to