Here is the interceptor (before I added the read only stuff):
Code:
public class CMSDKTransactionInterceptor implements MethodInterceptor
{
private Log _log = LogFactory.getLog(this.getClass());
private static ThreadLocal _threadLocal = new ThreadLocal();
/**
* Check if this interceptor has already been applied
* @return true if already applied
*/
private boolean interceptorAlreadyInProgress()
{
return _threadLocal.get() != null;
}
/**
* Set the interceptor to in progress for this thread so it is not applied twice
*/
private void setInterceptorInProgress()
{
_threadLocal.set(Boolean.TRUE);
}
/**
* Unset interceptor to in progress for this thread
*/
private void unsetInterceptorInProgress()
{
_threadLocal.set(null);
}
/**
* Begin a cmsdk transaction
* @param methodInvocation methodInvocation object
* @return whatever the underlying method returns
* @throws Throwable excption here on in uderlying method
*/
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
if (interceptorAlreadyInProgress())
{
_log.debug(" Aspect has already been applied... nothing to do");
Object ret = methodInvocation.proceed();
return ret;
}
else
{
try
{
//set a thread local to indicate that this interceptor has been applied
setInterceptorInProgress();
//get the LibrarySession ascosiated with the current request
LibrarySession ls = LibrarySessionHelper.getCurrentLibrarySession();
Transaction transaction = null;
//if there is a library session acsosiated with this request,
//begin a transaction
if (ls != null)
{
transaction = ls.beginTransaction();
}
else
{
_log.warn("No Libary Session found for this request... " +
"this request will not be transactional");
}
try
{
Object retVal = methodInvocation.proceed();
if (ls != null && transaction != null)
{
if (transaction.isCompleteable())
{
_log.debug("Completing transaction " + transaction);
ls.completeTransaction(transaction);
}
else
{
_log.warn("Unable to complete transaction: Transaction.isCompleteable() is false");
}
}
return retVal;
}
catch (Exception e)
{
if (ls != null && transaction != null)
{
try
{
ls.abortTransaction(transaction);
}
catch (IfsException ifse)
{
//dont rethrow this exception as the causing exception will be lost,
_log.info("Transaction Rollback failed", ifse);
}
}
throw e;
}
}
finally
{
//always unset the thread local as this interceptor is complete
unsetInterceptorInProgress();
}
}
}
}
I use ThreadLocal again to associate the users library session with the thread serving the current request.
Code:
public class LibrarySessionHelper
{
/**
* Thread local to hold the library session reference
*/
private static ThreadLocal _threadLocal = new ThreadLocal();
/**
* Private constructor to prevent instantiation
*/
private LibrarySessionHelper()
{
}
/**
* Set the LibrarySession to be available for the remainder of the request
* @param ls the LibrarySession
*/
public static void setLibrarySession(LibrarySession ls)
{
_threadLocal.set(ls);
}
/**
* remove the LibrarySession as the current request is complete.
*/
public static void removeLibrarySession()
{
_threadLocal.set(null);
}
/**
* get the LibrarySession ascosiated with this request
* @return the LibrarySession
*/
public static LibrarySession getCurrentLibrarySession()
{
return (LibrarySession)_threadLocal.get();
}
}
And a servlet filter to get the library session from the http session and call LibrarySessionHelper.setLibrarySession():
Code:
public class CMSDKTransactionFilter implements Filter
{
/**
* does nothing
* @param filterConfig the FilterConfig object
*/
public void init(FilterConfig filterConfig)
{
}
/**
* does nothing
*/
public void destroy()
{
}
/**
* The doFilter() method is called on every request, this implementation<br>
* 1: Gets the LibrarySession object out of the session and ascosiates it with the current thread<br>
* 2: Processes the remainder of the request <br>
* 3: Removes the LibrarySession from the current thread
*
* @param servletRequest The ServletRequest object
* @param servletResponse The ServletResponse object
* @param filterChain Object representing the remainder of the filter chain
* @throws IOException exception thrown elsewhere in the chain
* @throws ServletException exception thrown elsewhere in the chain
*/
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException
{
try
{
//if this is a http servlet request, get the LibrarySession out of the
//Session and ascosiate it with the request
if( servletRequest instanceof HttpServletRequest )
{
HttpServletRequest httpServletRequest = ( HttpServletRequest ) servletRequest;
//get the current session but dont create one if it doesnt already exist
HttpSession session = httpServletRequest.getSession( false );
LibrarySession librarySession = null;
if( session != null )
{
librarySession = ( LibrarySession ) session.getAttribute( LibrarySession.class.getName() );
}
//set the library session to make it available for the remainder of the request
LibrarySessionHelper.setLibrarySession( librarySession );
}
filterChain.doFilter( servletRequest, servletResponse );
}
finally
{
//always remove the libary session from the current thread at the end of the request
LibrarySessionHelper.removeLibrarySession();
}
}
}
I hope this is of some use!
Feel free to message me if you need any more info or i missed anything.