- EJB module has:
- Some CMP beans (with @ManyToOne and @OneToMany relationships);
- A Session Facade (stateless local bean).
- WEB module has:
- A jMaki-powered menu tree;
- A JSF-managed bean (that populates the jMaki tree with a call to Session Facade).
Googleing this problem, I found that the transaction of a stateless bean (using a "requires" or "requires new" attribute) is closed after the method returns, if the container opened it. Specifically, it happens when the EntityManager is destroyed. This is obvious, but not very intuitive. Solutions:
- Use a stateful bean. The Entity Manager will "survive" along with the session, but I think this will make the transaction survive that long, too. Not the best solution;
- Open the transaction in web container. This is strange, but logical: if I want to access the database (with lazy fetching), I must have an active transaction. EJB container is prepared to reuse the transaction by using the @TransactionAttribute annotation (defaults to "REQUIRED"). Using the brand-new resource injection, it is a matter of creating a "@Resource UserTransaction tx" attribute on my JSF managed bean. It is not nice to inject a transaction on every bean of web container, so, you only need to create a web filter that opens before chaining the operation.
public class TransactionFilter implements Filter {
@Resource
private UserTransaction tx;
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
try {
if (tx.getStatus() == STATUS_NO_TRANSACTION) {
tx.begin();
}
} catch (NotSupportedException ex) {
throw new ServletException(ex);
} catch (SystemException ex) {
throw new ServletException(ex);
}
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}