package org.jboss.seam.security.external.dialogues; import java.lang.annotation.Annotation; import java.util.UUID; import javax.enterprise.context.ContextNotActiveException; import javax.enterprise.context.spi.Context; import javax.enterprise.context.spi.Contextual; import javax.enterprise.context.spi.CreationalContext; import javax.servlet.ServletContext; import org.jboss.seam.security.external.contexts.ContextualInstance; import org.jboss.seam.security.external.contexts.HashMapBeanStore; import org.jboss.seam.security.external.dialogues.api.DialogueScoped; /** * @author Marcel Kolsteren */ public class DialogueContext implements Context { private static final String BEAN_STORE_ATTRIBUTE_NAME_PREFIX = "DialogueContextBeanStore"; private ServletContext servletContext; private final ThreadLocal<String> dialogueIdThreadLocal; public DialogueContext() { dialogueIdThreadLocal = new ThreadLocal<String>(); } protected HashMapBeanStore getBeanStore() { return getBeanStore(dialogueIdThreadLocal.get()); } private HashMapBeanStore getBeanStore(String dialogueId) { HashMapBeanStore beanStore = (HashMapBeanStore) servletContext.getAttribute(getAttributeName(dialogueId)); return beanStore; } private void createBeanStore(String dialogueId) { HashMapBeanStore beanStore = new HashMapBeanStore(); servletContext.setAttribute(getAttributeName(dialogueId), beanStore); } private void removeBeanStore(String dialogueId) { servletContext.removeAttribute(getAttributeName(dialogueId)); } private String getAttributeName(String dialogueId) { return BEAN_STORE_ATTRIBUTE_NAME_PREFIX + "_" + dialogueId; } public void initialize(ServletContext servletContext) { this.servletContext = servletContext; } public void destroy() { this.servletContext = null; } public String create() { if (this.dialogueIdThreadLocal.get() != null) { throw new RuntimeException("Already attached to a dialogue"); } String dialogueId; do { dialogueId = UUID.randomUUID().toString(); } while (getBeanStore(dialogueId) != null); this.dialogueIdThreadLocal.set(dialogueId); createBeanStore(dialogueId); return dialogueId; } public void remove() { getBeanStore().clear(); removeBeanStore(this.dialogueIdThreadLocal.get()); this.dialogueIdThreadLocal.set(null); } public boolean isExistingDialogue(String dialogueId) { return getBeanStore(dialogueId) != null; } /** * Attaches an existing dialogue to the current thread * * @param dialogueIdThreadLocal */ public void attach(String dialogueId) { if (this.dialogueIdThreadLocal.get() != null) { throw new RuntimeException("Already attached to a dialogue"); } if (!isExistingDialogue(dialogueId)) { throw new RuntimeException("There is no active context with request id " + dialogueId); } this.dialogueIdThreadLocal.set(dialogueId); } /** * Detaches the dialogue from the current thread */ public void detach() { this.dialogueIdThreadLocal.set(null); } public boolean isAttached() { return dialogueIdThreadLocal.get() != null; } public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { if (!isActive()) { throw new ContextNotActiveException(); } ContextualInstance<T> beanInstance = getBeanStore().get(contextual); if (beanInstance != null) { return beanInstance.getInstance(); } else if (creationalContext != null) { T instance = contextual.create(creationalContext); if (instance != null) { beanInstance = new ContextualInstance<T>(contextual, creationalContext, instance); getBeanStore().put(contextual, beanInstance); } return instance; } else { return null; } } public <T> T get(Contextual<T> contextual) { return get(contextual, null); } public Class<? extends Annotation> getScope() { return DialogueScoped.class; } public boolean isActive() { return dialogueIdThreadLocal.get() != null; } }