package org.pentaho.platform.engine.core.system;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.engine.core.messages.Messages;
/**
* An {@code InheritableThreadLocal}-based implementation of {@link IPentahoSessionHolderStrategy}.
*
* @author mlowery
*/
public class InheritableThreadLocalPentahoSessionHolderStrategy implements IPentahoSessionHolderStrategy {
// ~ Static fields/initializers ======================================================================================
private static final Log logger = LogFactory.getLog(InheritableThreadLocalPentahoSessionHolderStrategy.class);
// ~ Instance fields =================================================================================================
private static final ThreadLocal<IPentahoSession> perThreadSession = new InheritableThreadLocal<IPentahoSession>();
// ~ Constructors ====================================================================================================
public InheritableThreadLocalPentahoSessionHolderStrategy() {
super();
}
// ~ Methods =========================================================================================================
/**
* Sets an IPentahoSession for the current thread
* @param session
*/
public void setSession(IPentahoSession session) {
perThreadSession.set(session);
}
/**
* Returns the IPentahoSession for the current thread
* @return thread session
*/
public IPentahoSession getSession() {
IPentahoSession sess = perThreadSession.get();
if (sess == null) {
//In a perfect world, the platform should never be in a state where session is null, but we are not there yet. Not all places
//that instance sessions use the PentahoSessionHolder yet, so we will not make a fuss here if session is null. When PentahoSessionHolder
//is fully integrated with all sessions, then we should probably throw an exception here since in that case a null session means
//the system is in an illegal state.
logger.debug(Messages.getInstance().getString(
"PentahoSessionHolder.WARN_THREAD_SESSION_NULL", Thread.currentThread().getName())); //$NON-NLS-1$
}
return sess;
}
/**
* Removes the IPentahoSession for the current thread.
* It is important that the framework calls this to prevent session bleed-
* through between requests as threads are re-used by the server.
*/
public void removeSession() {
IPentahoSession sess = perThreadSession.get();
if (sess != null) {
if (logger.isDebugEnabled()) {
logger.debug(Messages.getInstance().getString("PentahoSessionHolder.DEBUG_REMOVING_SESSION",//$NON-NLS-1$
Thread.currentThread().getName(), String.valueOf(Thread.currentThread().getId())));
}
if (logger.isTraceEnabled()) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
logger.trace(Messages.getInstance().getString("PentahoSessionHolder.DEBUG_THREAD_STACK_TRACE"));//$NON-NLS-1$
for (int i = 0; i < elements.length; i++) {
logger.trace(elements[i]);
}
}
//If the session is a custom/stand-alone session, we need to remove references
//to it from other objects which may be holding on to it. We do this to prevent
//memory leaks. In the future, this should not be necessary since objects
//should not need to have setSesssion methods, but instead use PentahoSessionHolder.getSession()
if (sess instanceof StandaloneSession) {
if (logger.isDebugEnabled()) {
logger.debug(Messages.getInstance().getString("PentahoSessionHolder.DEBUG_DESTROY_STANDALONE_SESSION",//$NON-NLS-1$
String.valueOf(sess.getId()), sess.getName(), String.valueOf(Thread.currentThread().getId())));
}
((StandaloneSession) sess).destroy();
}
perThreadSession.remove();
}
}
}