/**
* Created on Sep 12, 2005
*
* $Id: OpenSessionInViewFilter.java,v 1.2 2006/03/07 13:09:30 costin Exp $
* $Revision: 1.2 $
*/
package org.springmodules.jcr.support;
import java.io.IOException;
import javax.jcr.Session;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springmodules.jcr.SessionFactory;
import org.springmodules.jcr.SessionFactoryUtils;
/**
* Servlet 2.3 Filter that binds a JCR Session to the thread for the
* entire processing of the request. Intended for the "Open Session
* in View" pattern, i.e. to allow for lazy loading in web views despite the
* original transactions already being completed.
*
* <p>
* This filter works similar to the AOP JcrInterceptor: It just makes JCR
* Sessions available via the thread. It is suitable for
* non-transactional execution but also for business layer transactions via
* JcrTransactionManager or JtaTransactionManager. In the latter case,
* Sessions pre-bound by this filter will automatically be used for
* the transactions.
*
* <p>
* Looks up the SessionFactory in Spring's root web application
* context. Supports a "SessionFactoryBeanName" filter init-param in
* <code>web.xml</code>; the default bean name is
* "SessionFactory". Looks up the SessionFactory on each
* request, to avoid initialization order issues (when using
* ContextLoaderServlet, the root application context will get initialized
* <i>after</i> this filter).
*
* @author Costin Leau
*/
public class OpenSessionInViewFilter extends OncePerRequestFilter {
public static final String DEFAULT_JCR_SESSION_FACTORY_FACTORY_BEAN_NAME = "sessionFactory";
private String SessionFactoryBeanName = DEFAULT_JCR_SESSION_FACTORY_FACTORY_BEAN_NAME;
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context. Default is "SessionFactory".
*
* @see #DEFAULT_JCR_SESSION_FACTORY_FACTORY_BEAN_NAME
*/
public void setSessionFactoryBeanName(String SessionFactoryBeanName) {
this.SessionFactoryBeanName = SessionFactoryBeanName;
}
/**
* Return the bean name of the SessionFactory to fetch from
* Spring's root application context.
*/
protected String getSessionFactoryBeanName() {
return SessionFactoryBeanName;
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
SessionFactory sf = lookupSessionFactory(request);
Session session = null;
boolean participate = false;
if (TransactionSynchronizationManager.hasResource(sf)) {
// Do not modify the Session: just set the participate
// flag.
participate = true;
}
else {
logger.debug("Opening JCR session in OpenSessionInViewFilter");
session = SessionFactoryUtils.getSession(sf, true);
TransactionSynchronizationManager.bindResource(sf, sf.getSessionHolder(session));
}
try {
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
TransactionSynchronizationManager.unbindResource(sf);
logger.debug("Closing JCR session in OpenSessionInViewFilter");
SessionFactoryUtils.releaseSession(session, sf);
}
}
}
/**
* Look up the SessionFactory that this filter should use, taking
* the current HTTP request as argument.
* <p>
* Default implementation delegates to the
* <code>lookupSessionFactory</code> without arguments.
*
* @return the SessionFactory to use
* @see #lookupSessionFactory()
*/
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
return lookupSessionFactory();
}
/**
* Look up the SessionFactory that this filter should use. The
* default implementation looks for a bean with the specified name in
* Spring's root application context.
*
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
*/
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using session factory '"
+ getSessionFactoryBeanName()
+ "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
return (SessionFactory) wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
}