diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/AbstractLifecycleBootstrap.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/AbstractLifecycleBootstrap.java index 75a4850..1b8fb66 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/AbstractLifecycleBootstrap.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/AbstractLifecycleBootstrap.java @@ -130,22 +130,22 @@ public abstract class AbstractLifecycleBootstrap implement ViewContext tempViewContext = Beans.getReference(ViewContext.class); ConversationContext tempConversationContext = Beans.getReference(ConversationContext.class); - boolean requestActivatedHere = !tempRequestContext.isActive(); - boolean sessionActivatedHere = !tempSessionContext.isActive(); - boolean viewActivatedHere = !tempViewContext.isActive(); - boolean conversationActivatedHere = !tempConversationContext.isActive(); + boolean requestActivatedHere = tempRequestContext!=null && !tempRequestContext.isActive(); + boolean sessionActivatedHere = tempSessionContext!=null && !tempSessionContext.isActive(); + boolean viewActivatedHere = tempViewContext!=null && !tempViewContext.isActive(); + boolean conversationActivatedHere = tempConversationContext!=null && !tempConversationContext.isActive(); if (!registered) { - if (!tempRequestContext.isActive()) + if (tempRequestContext!=null && !tempRequestContext.isActive()) tempRequestContext.activate(); - if (!tempSessionContext.isActive()) + if (tempSessionContext!=null && !tempSessionContext.isActive()) tempSessionContext.activate(); - if (!tempViewContext.isActive()) + if (tempViewContext!=null && !tempViewContext.isActive()) tempViewContext.activate(); - if (!tempConversationContext.isActive()) + if (tempConversationContext!=null && !tempConversationContext.isActive()) tempConversationContext.activate(); registered = true; diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/CustomContextBootstrap.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/CustomContextBootstrap.java index 846c706..1043176 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/CustomContextBootstrap.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/CustomContextBootstrap.java @@ -10,10 +10,11 @@ import javax.enterprise.inject.spi.ProcessAnnotatedType; import br.gov.frameworkdemoiselle.context.CustomContext; import br.gov.frameworkdemoiselle.context.StaticContext; -import br.gov.frameworkdemoiselle.internal.context.TemporaryRequestContextImpl; -import br.gov.frameworkdemoiselle.internal.context.TemporarySessionContextImpl; +import br.gov.frameworkdemoiselle.internal.context.ContextualStore; import br.gov.frameworkdemoiselle.internal.context.StaticContextImpl; import br.gov.frameworkdemoiselle.internal.context.TemporaryConversationContextImpl; +import br.gov.frameworkdemoiselle.internal.context.TemporaryRequestContextImpl; +import br.gov.frameworkdemoiselle.internal.context.TemporarySessionContextImpl; import br.gov.frameworkdemoiselle.internal.context.TemporaryViewContextImpl; import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess; @@ -28,6 +29,8 @@ public class CustomContextBootstrap implements Extension{ private List contexts; + private final ContextualStore contextualStore = new ContextualStore(); + public void vetoCustomContexts(@Observes ProcessAnnotatedType event){ //Veta os subtipos de CustomContext, para que não conflitem com o produtor de contextos personalizados. if( CustomContext.class.isAssignableFrom( event.getAnnotatedType().getJavaClass() )){ @@ -79,10 +82,15 @@ public class CustomContextBootstrap implements Extension{ } contexts.clear(); + contextualStore.clear(); } } public List getCustomContexts(){ return this.contexts; } + + public ContextualStore getContextualStore(){ + return this.contextualStore; + } } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java index f713f1e..2e0f39a 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java @@ -43,11 +43,14 @@ 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.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import org.slf4j.Logger; +import br.gov.frameworkdemoiselle.DemoiselleException; import br.gov.frameworkdemoiselle.context.CustomContext; +import br.gov.frameworkdemoiselle.internal.bootstrap.CustomContextBootstrap; import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer; import br.gov.frameworkdemoiselle.util.Beans; import br.gov.frameworkdemoiselle.util.ResourceBundle; @@ -58,7 +61,7 @@ public abstract class AbstractCustomContext implements CustomContext { private final Class scope; - private Logger logger; + private transient Logger logger; private transient ResourceBundle bundle; @@ -69,8 +72,6 @@ public abstract class AbstractCustomContext implements CustomContext { protected abstract BeanStore getStore(); - protected abstract ContextualStore getContextualStore(); - protected abstract boolean isStoreInitialized(); @Override @@ -87,23 +88,24 @@ public abstract class AbstractCustomContext implements CustomContext { throw new ContextNotActiveException(); } - String id = getContextualStore().tryRegisterAndGetId(contextual); - if (getStore().contains(id)) { - instance = (T) getStore().getInstance(id); - } - else if (creationalContext!=null){ - instance = contextual.create(creationalContext); - getStore().put(id, instance,creationalContext); + String id = getContextualStore().putIfAbsentAndGetId(contextual); + BeanStore store = getStore(); + if (store!=null){ + if (store.contains(id)) { + instance = (T) store.getInstance(id); + } + else if (creationalContext!=null){ + instance = contextual.create(creationalContext); + store.put(id, instance,creationalContext); + } + } + else{ + throw new DemoiselleException(getBundle().getString("store-not-found" , ((Bean)contextual).getBeanClass().getName() , getScope().getName())); } return instance; } - /*private Class getType(final Contextual contextual) { - Bean bean = (Bean) contextual; - return bean.getBeanClass(); - }*/ - @Override public boolean isActive() { return this.active; @@ -134,20 +136,11 @@ public abstract class AbstractCustomContext implements CustomContext { return this.active; } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void deactivate(){ if (this.active){ if (isStoreInitialized()){ - for (String id : getStore()){ - Contextual contextual = getContextualStore().getContextual(id); - Object instance = getStore().getInstance(id); - CreationalContext creationalContext = getStore().getCreationalContext(id); - - if (contextual!=null && instance!=null){ - contextual.destroy(instance, creationalContext); - } - } + clearInstances(); getStore().clear(); getContextualStore().clear(); @@ -160,7 +153,23 @@ public abstract class AbstractCustomContext implements CustomContext { logger.debug( bundle.getString("custom-context-was-deactivated" , this.getClass().getCanonicalName() , this.getScope().getSimpleName() ) ); } } - + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void clearInstances(){ + BeanStore store = getStore(); + if (store!=null){ + for (String id : store){ + Contextual contextual = getContextualStore().getContextual(id); + Object instance = store.getInstance(id); + CreationalContext creationalContext = store.getCreationalContext(id); + + if (contextual!=null && instance!=null){ + contextual.destroy(instance, creationalContext); + } + } + } + } + @Override public Class getScope() { return this.scope; @@ -190,6 +199,11 @@ public abstract class AbstractCustomContext implements CustomContext { return logger; } + ContextualStore getContextualStore(){ + CustomContextBootstrap bootstrap = Beans.getReference(CustomContextBootstrap.class); + return bootstrap.getContextualStore(); + } + @Override public boolean equals(Object obj) { if (this == obj) diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractStaticContext.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractStaticContext.java index 773884c..31c7175 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractStaticContext.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractStaticContext.java @@ -63,8 +63,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext { private final static Map staticBeanStore = Collections.synchronizedMap(new HashMap()); - private final static Map staticContextualStore = Collections.synchronizedMap(new HashMap()); - /** * Constructs this context to control the provided scope */ @@ -84,17 +82,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext { } @Override - protected ContextualStore getContextualStore() { - ContextualStore store = staticContextualStore.get( this.getClass().getCanonicalName() ); - if (store==null){ - store = createContextualStore(); - staticContextualStore.put(this.getClass().getCanonicalName(), store); - } - - return store; - } - - @Override protected boolean isStoreInitialized() { return staticBeanStore!=null; } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractThreadLocalContext.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractThreadLocalContext.java index bb67f5c..3978285 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractThreadLocalContext.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractThreadLocalContext.java @@ -61,8 +61,6 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext { private final ThreadLocal threadLocalBeans = new ThreadLocal(); - private final ThreadLocal threadLocalContextual = new ThreadLocal(); - AbstractThreadLocalContext(final Class scope) { super(scope); } @@ -80,13 +78,4 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext { return this.threadLocalBeans.get(); } - - @Override - protected ContextualStore getContextualStore() { - if (this.threadLocalContextual.get() == null) { - this.threadLocalContextual.set(createContextualStore()); - } - - return this.threadLocalContextual.get(); - } } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/BeanStore.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/BeanStore.java index d672b81..371522c 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/BeanStore.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/BeanStore.java @@ -1,10 +1,9 @@ package br.gov.frameworkdemoiselle.internal.context; import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.enterprise.context.spi.CreationalContext; @@ -13,14 +12,12 @@ public class BeanStore implements Iterable,Serializable { private static final long serialVersionUID = 1L; - private Map instanceCache = Collections.synchronizedMap( new HashMap() ); - private Map creationalCache = Collections.synchronizedMap( new HashMap() );; + private ConcurrentMap instanceCache = new ConcurrentHashMap(); + private ConcurrentMap creationalCache = new ConcurrentHashMap(); public void put(String id, T instance,CreationalContext creationalContext){ - if (!instanceCache.containsKey(id)){ - instanceCache.put(id, instance); - creationalCache.put(id, creationalContext); - } + instanceCache.putIfAbsent(id, instance); + creationalCache.putIfAbsent(id, creationalContext); } public Object getInstance(String id){ @@ -44,5 +41,4 @@ public class BeanStore implements Iterable,Serializable { public Iterator iterator() { return instanceCache.keySet().iterator(); } - } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java index 53e3724..3ba7643 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java @@ -1,7 +1,8 @@ package br.gov.frameworkdemoiselle.internal.context; import java.io.Serializable; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import javax.enterprise.context.spi.Contextual; @@ -15,46 +16,75 @@ public class ContextualStore implements Serializable { private static final String PREFIX = ContextualStore.class.getCanonicalName() + "#"; - private AtomicInteger idGenerator = new AtomicInteger(); + private final AtomicInteger idGenerator = new AtomicInteger(); - private HashMap idToContextual = new HashMap(); - - private HashMap contextualToId = new HashMap(); + /* + * BASEADO NA IMPLEMENTAÇÃO DE CDI DO WELD + * + * Contextuals (instâncias de Bean) implementam a interface PassivationCapable quando são capazes + * de participar em um cluster de servidores, dessa forma o mesmo Bean pode ser usado para criar instâncias + * em todos os servidores e o ciclo de vida é síncrono + * + * Se o contextual não implementar PassivationCapable esse suporte não é possível. Por isso o WELD armazena + * separadamente contextuals que implementam PassivationCapable e que não implementam. + * + * A implementação abaixo foi baseada nesse comportamento, afim de evitar problemas em aplicações empacotadas em EAR + * e servidores de aplicação em cluster. + * + */ + private final ConcurrentMap idToContextual = new ConcurrentHashMap(); + private final ConcurrentMap contextualToId = new ConcurrentHashMap(); + private final ConcurrentMap passivableIdToContextual = new ConcurrentHashMap(); /** - * The an unique ID for the given contextual. If it's the first time + * Return an unique ID for the given contextual. If it's the first time * this contextual is accessed, registers the contextual for latter retrieval. * * @param contextual The contextual to generate an ID * @return The unique ID for the contextual */ - public String tryRegisterAndGetId(Contextual contextual){ + public String putIfAbsentAndGetId(Contextual contextual){ String returnedId; - if (contextualToId.containsKey(contextual)){ - returnedId = contextualToId.get(contextual); - } - else if (contextual instanceof PassivationCapable){ + if (contextual instanceof PassivationCapable){ returnedId = ((PassivationCapable)contextual).getId(); - idToContextual.put(returnedId, contextual); - contextualToId.put(contextual, returnedId); + passivableIdToContextual.putIfAbsent(returnedId, contextual); } else{ - returnedId = PREFIX + idGenerator.addAndGet(1); - idToContextual.put(returnedId, contextual); - contextualToId.put(contextual, returnedId); + returnedId = contextualToId.get(contextual); + if (returnedId==null){ + synchronized (contextual) { + //Esse código é uma implementação de performance. Se já existia + //ID para um contextual, retornamos. Do contrário precisamos fazer uma operação threadsafe + //que será cara. Então separamos a possibilide do ID já existir (a mais comum) fora do bloco + //synchronized, mas se precisarmos entrar no bloco precisamos perguntar pelo ID + //novamente, caso outra thread tenha criado o ID entre a primeira pergunta e a geração do ID. + returnedId = contextualToId.get(contextual); + if (returnedId==null){ + returnedId = new StringBuffer().append(PREFIX).append(idGenerator.incrementAndGet()).toString(); + idToContextual.put(returnedId, contextual); + contextualToId.put(contextual, returnedId); + } + } + } } return returnedId; } public Contextual getContextual(String id){ - return idToContextual.get(id); + if (id.startsWith(PREFIX)){ + return idToContextual.get(id); + } + else{ + return passivableIdToContextual.get(id); + } } public void clear(){ idToContextual.clear(); contextualToId.clear(); + passivableIdToContextual.clear(); } } diff --git a/impl/core/src/main/resources/demoiselle-core-bundle.properties b/impl/core/src/main/resources/demoiselle-core-bundle.properties index 7b01c11..6124859 100644 --- a/impl/core/src/main/resources/demoiselle-core-bundle.properties +++ b/impl/core/src/main/resources/demoiselle-core-bundle.properties @@ -39,6 +39,7 @@ key-not-found=A chave {0} n\u00E3o foi encontrada ambiguous-strategy-resolution=Foi detectada ambiguidade da interface {0} com as seguintes implementa\u00E7\u00F5es\: {1}. Para resolver o conflito, defina explicitamente a implementa\u00E7\u00E3o no demoiselle.properties. ambiguous-bean-resolution=Falha ao obter {0} pois foi detectada ambiguidade nas seguintes implementa\u00E7\u00F5es\: {1} bean-not-found=Voc\u00EA est\u00E1 tentando obter um objeto n\u00E3o reconhecido pelo CDI via Beans.getReference({0}) +store-not-found=O objeto do tipo [{0}] n\u00E3o pode ser armazenado no escopo indicado\: {1} more-than-one-exceptionhandler-defined-for-same-class=Foi definido mais de um m\u00E9todo na classe {0} para tratar a exce\u00E7\u00E3o {1} handling-exception=Tratando a exce\u00E7\u00E3o {0} taking-off=O Demoiselle ${project.version} decolou diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ViewScopeConfig.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ViewScopeConfig.java new file mode 100644 index 0000000..8b68e2c --- /dev/null +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ViewScopeConfig.java @@ -0,0 +1,59 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.internal.configuration; + +import java.io.Serializable; + +import br.gov.frameworkdemoiselle.annotation.Name; +import br.gov.frameworkdemoiselle.configuration.Configuration; + +@Configuration(prefix = "frameworkdemoiselle.scope.view") +public class ViewScopeConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @Name("timeout") + private int viewScopeTimeout = 1800; + + public int getViewScopeTimeout() { + return viewScopeTimeout; + } + + public void setViewScopeTimeout(int viewScopeTimeout) { + this.viewScopeTimeout = viewScopeTimeout; + } +} diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java index 5b70402..42aa35a 100644 --- a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java @@ -36,11 +36,14 @@ */ package br.gov.frameworkdemoiselle.internal.context; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; import javax.enterprise.inject.Alternative; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import br.gov.frameworkdemoiselle.annotation.Priority; import br.gov.frameworkdemoiselle.annotation.ViewScoped; @@ -59,37 +62,80 @@ import br.gov.frameworkdemoiselle.util.Faces; @Priority(Priority.L2_PRIORITY) @Alternative public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext { - + + private final AtomicLong atomicLong = new AtomicLong(); + + private ConcurrentHashMap sessionBeanStore = new ConcurrentHashMap(); + + private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName(); + public FacesViewContextImpl() { super(ViewScoped.class); } @Override protected boolean isStoreInitialized() { - return FacesContext.getCurrentInstance()!=null; + return FacesContext.getCurrentInstance()!=null && getSessionId()!=null; } @Override protected BeanStore getStore() { - Map viewMap = Faces.getViewMap(); - String key = BeanStore.class.getName(); - - if (!viewMap.containsKey(key)) { - viewMap.put(key, createStore()); + clearInvalidatedSession(); + + final String sessionId = getSessionId(); + + if (sessionId==null){ + return null; + } + + Long viewId = (Long)Faces.getViewMap().get(FACES_KEY); + if (viewId==null){ + synchronized (this) { + viewId = (Long)Faces.getViewMap().get(FACES_KEY); + if (viewId==null){ + viewId = atomicLong.incrementAndGet(); + Faces.getViewMap().put(FACES_KEY, viewId); + } + } } - return (BeanStore) viewMap.get(key); + SessionBeanStore currentStore = sessionBeanStore.get(sessionId); + if (currentStore==null){ + synchronized (this) { + currentStore = (SessionBeanStore) sessionBeanStore.get(sessionId); + if (currentStore==null){ + currentStore = new SessionBeanStore(); + sessionBeanStore.put(sessionId, currentStore); + } + } + } + + return currentStore.getStore(viewId, this); } - - @Override - protected ContextualStore getContextualStore() { - Map viewMap = Faces.getViewMap(); - String key = ContextualStore.class.getName(); - - if (!viewMap.containsKey(key)) { - viewMap.put(key, createContextualStore()); + + private synchronized void clearInvalidatedSession(){ + if (wasSessionInvalidated()){ + final String requestedSessionId = getRequestedSessionId(); + final SessionBeanStore store = sessionBeanStore.get(requestedSessionId); + if (store!=null){ + store.clear(this); + sessionBeanStore.remove(requestedSessionId); + } } - - return (ContextualStore) viewMap.get(key); + } + + private String getSessionId(){ + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true); + return session!=null ? session.getId() : null; + } + + private String getRequestedSessionId(){ + final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); + return request!=null ? request.getRequestedSessionId() : null; + } + + private boolean wasSessionInvalidated(){ + final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); + return request!=null && request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid(); } } diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/SessionBeanStore.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/SessionBeanStore.java new file mode 100644 index 0000000..e2b5d68 --- /dev/null +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/SessionBeanStore.java @@ -0,0 +1,43 @@ +package br.gov.frameworkdemoiselle.internal.context; + +import java.io.Serializable; + +import javax.enterprise.context.SessionScoped; +import javax.enterprise.context.spi.Contextual; +import javax.enterprise.context.spi.CreationalContext; + +@SessionScoped +public class SessionBeanStore implements Serializable { + + private static final long serialVersionUID = -8265458933971929432L; + + private Long lastViewId = null; + + private BeanStore store; + + synchronized BeanStore getStore(Long viewId, AbstractCustomContext context) { + if (lastViewId == null || !lastViewId.equals(viewId)) { + clear(context); + lastViewId = viewId; + store = AbstractCustomContext.createStore(); + } + + return store; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void clear(AbstractCustomContext context) { + if (store != null) { + for (String id : store) { + Contextual contextual = context.getContextualStore().getContextual(id); + Object instance = store.getInstance(id); + CreationalContext creationalContext = store.getCreationalContext(id); + + if (contextual != null && instance != null) { + contextual.destroy(instance, creationalContext); + } + } + store.clear(); + } + } +} diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Faces.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Faces.java index e27db36..77f90d7 100644 --- a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Faces.java +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Faces.java @@ -171,4 +171,9 @@ public class Faces { UIViewRoot viewRoot = getFacesContext().getViewRoot(); return viewRoot.getViewMap(true); } + + public static String getCurrentViewId(){ + return getFacesContext().getViewRoot().getViewId(); + } + } -- libgit2 0.21.2