One way to do this extension is to use a servlet filter that manages the transactions at the request boundary.
public class TransactionFilter implements Filter {
/**
* Logger for the class
*/
private final static Logger logger = Logger.getLogger(TransactionFilter.class);
/**
* @param request The request that we serve
* @param response The response that we create
* @param chain The chain of other filters that may have been defined
* @throws IOException wraps any I/O related exception thrown during
* processing
* @throws ServletException wraps any exception thrown during processing
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
UserTransaction utx = null;
try {
Context ctx = new InitialContext();
Object ref = ctx.lookup("UserTransaction");
utx = (UserTransaction) PortableRemoteObject.narrow(ref, UserTransaction.class);
utx.begin();
chain.doFilter(request, response);
int status = utx.getStatus();
if (status == Status.STATUS_ACTIVE)
utx.commit();
else
utx.rollback();
}
catch (Throwable e){
try {
if ((utx != null) && (utx.getStatus() == Status.STATUS_ACTIVE))
utx.rollback();
}
catch (Throwable e1) {
logger.error("Cannot rollback transaction", e1);
}
if (e instanceof ServletException)
throw (ServletException) e;
if (e instanceof IOException)
throw (IOException) e;
if (e instanceof RuntimeException)
throw (RuntimeException) e;
throw new ServletException(e);
}
}
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig arg0) throws ServletException {
}
}
The filter begins a transaction at the beginning of each http request and commits at the end. Each call to session bean methods has already an active transaction associated so the session bean does not start a new one (if it is configured with TransactionAttribute REQUIRED). Thus the transaction and the associated hibernate session are active throughout the request and we can use the pojos in the action classes (struts, stripes) or in jsps without caring about uninitialized lazy fields.
Don't forget to configure the filter to intercept every request associated with the view layer e.g.
<filter-mapping>
<filter-name>TransactionFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>TransactionFilter</filter-name>
<servlet-name>StripesDispatcher</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>