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?
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();
}
}