/**
* Created on Sep 12, 2005
*
* $Id: JcrInterceptor.java,v 1.2 2006/03/07 13:09:29 costin Exp $
* $Revision: 1.2 $
*/
package org.springmodules.jcr;
import javax.jcr.Session;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* This interceptor binds a new Jcr Session to the thread before a method call,
* closing and removing it afterwards in case of any method outcome. If there
* already is a pre-bound Jcr Session (e.g. from JcrTransactionManager, or from
* a surrounding JCR-intercepted method), the interceptor simply participates in
* it.
*
* <p>
* Application code must retrieve a JCR Session via the
* <code>JcrSessionFactoryUtils.getSession</code> method, to be able to detect
* a thread-bound Jcr Session. It is preferable to use <code>getSession</code>
* with allowCreate=false, if the code relies on the interceptor to provide
* proper session handling. Typically, the code will look as follows:
*
* <pre>
* public void doJcrAction() {
* Session session = JcrSessionFactoryUtils.getSession(this.jsf, false);
* try {
* ...
* }
* catch (RepositoryException ex) {
* throw JcrSessionFactoryUtils.convertJcrAccessException(ex);
* }
* }
* </pre>
*
* Note that the application must care about handling RepositoryExceptions
* itself, preferably via delegating to the
* <code>JcrSessionFactoryUtils.convertJcrAccessException</code> method that
* converts them to exceptions that are compatible with the
* <code>org.springframework.dao</code> exception hierarchy (like JcrTemplate
* does).
*
* <p>
* This class can be considered a declarative alternative to JcrTemplate's
* callback approach. The advantages are:
* <ul>
* <li>no anonymous classes necessary for callback implementations;
* <li>the possibility to throw any application exceptions from within data
* access code.
* </ul>
*
* <p>
* The drawbacks are:
* <ul>
* <li>the dependency on interceptor configuration;
* <li>the delegating try/catch blocks.
* </ul>
*
* @author Costin Leau
*
*/
public class JcrInterceptor extends JcrAccessor implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
boolean existingTransaction = false;
Session session = SessionFactoryUtils.getSession(getSessionFactory(), true);
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
logger.debug("Found thread-bound Session for JCR interceptor");
existingTransaction = true;
} else {
logger.debug("Using new Session for JCR interceptor");
TransactionSynchronizationManager.bindResource(getSessionFactory(), getSessionFactory().getSessionHolder(session));
}
try {
Object retVal = methodInvocation.proceed();
// flushIfNecessary(session, existingTransaction);
return retVal;
} finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound JCR Session after interceptor");
} else {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
}
}