package org.jboss.weld.module.web.context.beanstore.http; import static java.util.Collections.emptyIterator; import static org.jboss.weld.util.reflection.Reflections.cast; import java.util.Iterator; import javax.servlet.http.HttpSession; import org.jboss.weld.context.api.ContextualInstance; import org.jboss.weld.contexts.beanstore.AttributeBeanStore; import org.jboss.weld.contexts.beanstore.LockStore; import org.jboss.weld.contexts.beanstore.NamingScheme; import org.jboss.weld.logging.ContextLogger; import org.jboss.weld.serialization.spi.BeanIdentifier; import org.jboss.weld.util.collections.EnumerationIterator; /** * Base class providing an HttpSession backed, bound bean store. * * @author Pete Muir * @author David Allen * @author Nicklas Karlsson * @see LazySessionBeanStore * @see EagerSessionBeanStore */ public abstract class AbstractSessionBeanStore extends AttributeBeanStore { private static final String SESSION_KEY = "org.jboss.weld.context.beanstore.http.LockStore"; private transient volatile LockStore lockStore; private static final ThreadLocal<LockStore> CURRENT_LOCK_STORE = new ThreadLocal<LockStore>(); protected abstract HttpSession getSession(boolean create); /** * * @param namingScheme * @param attributeLazyFetchingEnabled */ public AbstractSessionBeanStore(NamingScheme namingScheme, boolean attributeLazyFetchingEnabled) { super(namingScheme, attributeLazyFetchingEnabled); } protected Iterator<String> getAttributeNames() { HttpSession session = getSession(false); if (session == null) { return emptyIterator(); } else { return new EnumerationIterator<String>(session.getAttributeNames()); } } @Override protected void removeAttribute(String key) { HttpSession session = getSession(false); if (session != null) { session.removeAttribute(key); ContextLogger.LOG.removedKeyFromSession(key, this.getSession(false).getId()); } else { ContextLogger.LOG.unableToRemoveKeyFromSession(key); } } @Override protected void setAttribute(String key, Object instance) { HttpSession session = getSession(true); if (session != null) { session.setAttribute(key, instance); ContextLogger.LOG.addedKeyToSession(key, this.getSession(false).getId()); } else { ContextLogger.LOG.unableToAddKeyToSession(key); } } @Override public <T> ContextualInstance<T> get(BeanIdentifier id) { ContextualInstance<T> instance = super.get(id); if (instance == null && isAttached()) { String prefixedId = getNamingScheme().prefix(id); instance = cast(getAttribute(prefixedId)); } return instance; } @Override protected Object getAttribute(String prefixedId) { HttpSession session = getSession(false); if (session != null) { return session.getAttribute(prefixedId); } return null; } @Override protected LockStore getLockStore() { LockStore lockStore = this.lockStore; if (lockStore == null) { //needed to prevent some edge cases //where we would otherwise enter an infinite loop lockStore = CURRENT_LOCK_STORE.get(); if(lockStore != null) { return lockStore; } HttpSession session = getSession(false); if(session == null) { lockStore = new LockStore(); CURRENT_LOCK_STORE.set(lockStore); try { session = getSession(true); } finally { CURRENT_LOCK_STORE.remove(); } } lockStore = (LockStore) session.getAttribute(SESSION_KEY); if (lockStore == null) { //we don't really have anything we can lock on //so we just acquire a big global lock //this should only be taken on session creation though //so should not be a problem synchronized (AbstractSessionBeanStore.class) { lockStore = (LockStore) session.getAttribute(SESSION_KEY); if (lockStore == null) { lockStore = new LockStore(); session.setAttribute(SESSION_KEY, lockStore); } } } this.lockStore = lockStore; } return lockStore; } }