Search code examples
javatransactionsweblogicseambean-managed-transactions

Seam-managed transactions how-to


Seam advises using an Extended persistent context in a Stateful Session Bean, in order to have Seam-managed persistence.

I am not clear on whether the above advice casts any implications on the way we want to have Seam-managed transactions. This is because our architecture is different. We have the following persistence context in a Stateless EJB:

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class CrudServiceBean implements CrudService {

    @PersistenceContext(type = PersistenceContextType.TRANSACTION)
    private EntityManager em;
...
}

Our DAOs invoke the above CrudServiceBean are Stateless EJBs (some of them are also Seam components) with @TransactionAttribute(TransactionAttributeType.REQUIRED). So, our transactions are handled by the container (WebLogic) and not Seam.

However, we now need to satisfy the following scenario: We need to have a front-end Seam component (non-EJB) invoke multiple DAO (EJB) methods and wrap all of them in a single transaction. If I understand correctly, we need to have Seam-managed transactions.

Can we have Seam-managed transactions as in the scenario I described, without having a Seam-managed persistence context? Or are the two irrelevant?


Solution

  • As said

    We need to have a front-end Seam component (non-EJB) invoke multiple DAO (EJB) methods and wrap all of them in a single transaction

    But

    Our transactions are handled by the container - Also called Container Managed Transaction (The container Takes care of calling begin and commit method used by each underlying resource-manager Transaction)

    The first issue is that you have a scenario where a non-EJB invokes multiple DAOs, each one an EJB. You could think of

    @Name("nonEjbComponent")
    public class NonEjbComponent {
    
        private @In DaoEjbComponent daoEjbComponent;
        private @In OtherDaoEjbComponent otherDaoEjbComponent;
        private @In AnotherDaoEjbComponent anotherDaoEjbComponent;
    
        private @In UserTransaction userTransation;
    
        public void wrapperAllOfThem() {
    
             userTransation.begin();
    
                 daoEjbComponent.save(someEntity);
                 otherDaoEjbComponent.update(otherEntity);
                 anotherDaoEjbComponent.delete(anotherEntity);
    
             userTransation.commit();
    
        }
    
    }
    

    But the Java EE specification 3.0 states

    The enterprise bean with Either bean-managed or container-managed transaction demarcation must be a session bean or a message-driven bean.

    So you can not use the scenario above. And because all of your DAOs are using container-managed transactions, the Java EE specification does not allow you to use container-managed and bean-managed Transaction at the same time

    So the solution is

    Wrap all of the DAOs in an EJB Stateless session bean whose transaction is container-managed. It will behave like a delegate component

    @Stateless
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Name("wrapperStateless")
    public class WrapperStatelessImpl implements WrapperStateless {
    
        private @In DaoEjbComponent daoEjbComponent;
        private @In OtherDaoEjbComponent otherDaoEjbComponent;
        private @In AnotherDaoEjbComponent anotherDaoEjbComponent;
    
        public void wrapperAllOfThem() {
    
            daoEjbComponent.save(someEntity);
            otherDaoEjbComponent.update(otherEntity);
            anotherDaoEjbComponent.delete(anotherEntity);
    
        }
    
    }
    

    And inside your non-EJB component, use

    @Name("nonEjbComponent")
    public class NonEjbComponent {
    
        private @In WrapperStateless wrapperStateless;
    
        public void wrapperAllOfThem() {
            wrapperStateless.wrapperAllOfThem();
        }
    
    }