Commit 68f4ff71acf30b2677947a62ded34e2ea1f69ee2

Authored by Dancovich
1 parent 6d6405c4
Exists in master

Refatoração do contexto do escopo ViewScoped para permitir serialização

e terminar corretamente beans armazenados nesse escopo.
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/AbstractLifecycleBootstrap.java
... ... @@ -130,22 +130,22 @@ public abstract class AbstractLifecycleBootstrap<A extends Annotation> implement
130 130 ViewContext tempViewContext = Beans.getReference(ViewContext.class);
131 131 ConversationContext tempConversationContext = Beans.getReference(ConversationContext.class);
132 132  
133   - boolean requestActivatedHere = !tempRequestContext.isActive();
134   - boolean sessionActivatedHere = !tempSessionContext.isActive();
135   - boolean viewActivatedHere = !tempViewContext.isActive();
136   - boolean conversationActivatedHere = !tempConversationContext.isActive();
  133 + boolean requestActivatedHere = tempRequestContext!=null && !tempRequestContext.isActive();
  134 + boolean sessionActivatedHere = tempSessionContext!=null && !tempSessionContext.isActive();
  135 + boolean viewActivatedHere = tempViewContext!=null && !tempViewContext.isActive();
  136 + boolean conversationActivatedHere = tempConversationContext!=null && !tempConversationContext.isActive();
137 137  
138 138 if (!registered) {
139   - if (!tempRequestContext.isActive())
  139 + if (tempRequestContext!=null && !tempRequestContext.isActive())
140 140 tempRequestContext.activate();
141 141  
142   - if (!tempSessionContext.isActive())
  142 + if (tempSessionContext!=null && !tempSessionContext.isActive())
143 143 tempSessionContext.activate();
144 144  
145   - if (!tempViewContext.isActive())
  145 + if (tempViewContext!=null && !tempViewContext.isActive())
146 146 tempViewContext.activate();
147 147  
148   - if (!tempConversationContext.isActive())
  148 + if (tempConversationContext!=null && !tempConversationContext.isActive())
149 149 tempConversationContext.activate();
150 150  
151 151 registered = true;
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/CustomContextBootstrap.java
... ... @@ -10,10 +10,11 @@ import javax.enterprise.inject.spi.ProcessAnnotatedType;
10 10  
11 11 import br.gov.frameworkdemoiselle.context.CustomContext;
12 12 import br.gov.frameworkdemoiselle.context.StaticContext;
13   -import br.gov.frameworkdemoiselle.internal.context.TemporaryRequestContextImpl;
14   -import br.gov.frameworkdemoiselle.internal.context.TemporarySessionContextImpl;
  13 +import br.gov.frameworkdemoiselle.internal.context.ContextualStore;
15 14 import br.gov.frameworkdemoiselle.internal.context.StaticContextImpl;
16 15 import br.gov.frameworkdemoiselle.internal.context.TemporaryConversationContextImpl;
  16 +import br.gov.frameworkdemoiselle.internal.context.TemporaryRequestContextImpl;
  17 +import br.gov.frameworkdemoiselle.internal.context.TemporarySessionContextImpl;
17 18 import br.gov.frameworkdemoiselle.internal.context.TemporaryViewContextImpl;
18 19 import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
19 20  
... ... @@ -28,6 +29,8 @@ public class CustomContextBootstrap implements Extension{
28 29  
29 30 private List<CustomContext> contexts;
30 31  
  32 + private final ContextualStore contextualStore = new ContextualStore();
  33 +
31 34 public <T extends CustomContext> void vetoCustomContexts(@Observes ProcessAnnotatedType<T> event){
32 35 //Veta os subtipos de CustomContext, para que não conflitem com o produtor de contextos personalizados.
33 36 if( CustomContext.class.isAssignableFrom( event.getAnnotatedType().getJavaClass() )){
... ... @@ -79,10 +82,15 @@ public class CustomContextBootstrap implements Extension{
79 82 }
80 83  
81 84 contexts.clear();
  85 + contextualStore.clear();
82 86 }
83 87 }
84 88  
85 89 public List<CustomContext> getCustomContexts(){
86 90 return this.contexts;
87 91 }
  92 +
  93 + public ContextualStore getContextualStore(){
  94 + return this.contextualStore;
  95 + }
88 96 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractCustomContext.java
... ... @@ -43,11 +43,14 @@ import javax.enterprise.context.ContextNotActiveException;
43 43 import javax.enterprise.context.spi.Context;
44 44 import javax.enterprise.context.spi.Contextual;
45 45 import javax.enterprise.context.spi.CreationalContext;
  46 +import javax.enterprise.inject.spi.Bean;
46 47 import javax.enterprise.inject.spi.BeanManager;
47 48  
48 49 import org.slf4j.Logger;
49 50  
  51 +import br.gov.frameworkdemoiselle.DemoiselleException;
50 52 import br.gov.frameworkdemoiselle.context.CustomContext;
  53 +import br.gov.frameworkdemoiselle.internal.bootstrap.CustomContextBootstrap;
51 54 import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer;
52 55 import br.gov.frameworkdemoiselle.util.Beans;
53 56 import br.gov.frameworkdemoiselle.util.ResourceBundle;
... ... @@ -58,7 +61,7 @@ public abstract class AbstractCustomContext implements CustomContext {
58 61  
59 62 private final Class<? extends Annotation> scope;
60 63  
61   - private Logger logger;
  64 + private transient Logger logger;
62 65  
63 66 private transient ResourceBundle bundle;
64 67  
... ... @@ -69,8 +72,6 @@ public abstract class AbstractCustomContext implements CustomContext {
69 72  
70 73 protected abstract BeanStore getStore();
71 74  
72   - protected abstract ContextualStore getContextualStore();
73   -
74 75 protected abstract boolean isStoreInitialized();
75 76  
76 77 @Override
... ... @@ -87,23 +88,24 @@ public abstract class AbstractCustomContext implements CustomContext {
87 88 throw new ContextNotActiveException();
88 89 }
89 90  
90   - String id = getContextualStore().tryRegisterAndGetId(contextual);
91   - if (getStore().contains(id)) {
92   - instance = (T) getStore().getInstance(id);
93   - }
94   - else if (creationalContext!=null){
95   - instance = contextual.create(creationalContext);
96   - getStore().put(id, instance,creationalContext);
  91 + String id = getContextualStore().putIfAbsentAndGetId(contextual);
  92 + BeanStore store = getStore();
  93 + if (store!=null){
  94 + if (store.contains(id)) {
  95 + instance = (T) store.getInstance(id);
  96 + }
  97 + else if (creationalContext!=null){
  98 + instance = contextual.create(creationalContext);
  99 + store.put(id, instance,creationalContext);
  100 + }
  101 + }
  102 + else{
  103 + throw new DemoiselleException(getBundle().getString("store-not-found" , ((Bean<?>)contextual).getBeanClass().getName() , getScope().getName()));
97 104 }
98 105  
99 106 return instance;
100 107 }
101 108  
102   - /*private <T> Class<?> getType(final Contextual<T> contextual) {
103   - Bean<T> bean = (Bean<T>) contextual;
104   - return bean.getBeanClass();
105   - }*/
106   -
107 109 @Override
108 110 public boolean isActive() {
109 111 return this.active;
... ... @@ -134,20 +136,11 @@ public abstract class AbstractCustomContext implements CustomContext {
134 136 return this.active;
135 137 }
136 138  
137   - @SuppressWarnings({ "rawtypes", "unchecked" })
138 139 @Override
139 140 public void deactivate(){
140 141 if (this.active){
141 142 if (isStoreInitialized()){
142   - for (String id : getStore()){
143   - Contextual contextual = getContextualStore().getContextual(id);
144   - Object instance = getStore().getInstance(id);
145   - CreationalContext creationalContext = getStore().getCreationalContext(id);
146   -
147   - if (contextual!=null && instance!=null){
148   - contextual.destroy(instance, creationalContext);
149   - }
150   - }
  143 + clearInstances();
151 144  
152 145 getStore().clear();
153 146 getContextualStore().clear();
... ... @@ -160,7 +153,23 @@ public abstract class AbstractCustomContext implements CustomContext {
160 153 logger.debug( bundle.getString("custom-context-was-deactivated" , this.getClass().getCanonicalName() , this.getScope().getSimpleName() ) );
161 154 }
162 155 }
163   -
  156 +
  157 + @SuppressWarnings({ "rawtypes", "unchecked" })
  158 + public void clearInstances(){
  159 + BeanStore store = getStore();
  160 + if (store!=null){
  161 + for (String id : store){
  162 + Contextual contextual = getContextualStore().getContextual(id);
  163 + Object instance = store.getInstance(id);
  164 + CreationalContext creationalContext = store.getCreationalContext(id);
  165 +
  166 + if (contextual!=null && instance!=null){
  167 + contextual.destroy(instance, creationalContext);
  168 + }
  169 + }
  170 + }
  171 + }
  172 +
164 173 @Override
165 174 public Class<? extends Annotation> getScope() {
166 175 return this.scope;
... ... @@ -190,6 +199,11 @@ public abstract class AbstractCustomContext implements CustomContext {
190 199 return logger;
191 200 }
192 201  
  202 + ContextualStore getContextualStore(){
  203 + CustomContextBootstrap bootstrap = Beans.getReference(CustomContextBootstrap.class);
  204 + return bootstrap.getContextualStore();
  205 + }
  206 +
193 207 @Override
194 208 public boolean equals(Object obj) {
195 209 if (this == obj)
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractStaticContext.java
... ... @@ -63,8 +63,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext {
63 63  
64 64 private final static Map<String, BeanStore> staticBeanStore = Collections.synchronizedMap(new HashMap<String, BeanStore>());
65 65  
66   - private final static Map<String, ContextualStore> staticContextualStore = Collections.synchronizedMap(new HashMap<String, ContextualStore>());
67   -
68 66 /**
69 67 * Constructs this context to control the provided scope
70 68 */
... ... @@ -84,17 +82,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext {
84 82 }
85 83  
86 84 @Override
87   - protected ContextualStore getContextualStore() {
88   - ContextualStore store = staticContextualStore.get( this.getClass().getCanonicalName() );
89   - if (store==null){
90   - store = createContextualStore();
91   - staticContextualStore.put(this.getClass().getCanonicalName(), store);
92   - }
93   -
94   - return store;
95   - }
96   -
97   - @Override
98 85 protected boolean isStoreInitialized() {
99 86 return staticBeanStore!=null;
100 87 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/AbstractThreadLocalContext.java
... ... @@ -61,8 +61,6 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext {
61 61  
62 62 private final ThreadLocal<BeanStore> threadLocalBeans = new ThreadLocal<BeanStore>();
63 63  
64   - private final ThreadLocal<ContextualStore> threadLocalContextual = new ThreadLocal<ContextualStore>();
65   -
66 64 AbstractThreadLocalContext(final Class<? extends Annotation> scope) {
67 65 super(scope);
68 66 }
... ... @@ -80,13 +78,4 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext {
80 78  
81 79 return this.threadLocalBeans.get();
82 80 }
83   -
84   - @Override
85   - protected ContextualStore getContextualStore() {
86   - if (this.threadLocalContextual.get() == null) {
87   - this.threadLocalContextual.set(createContextualStore());
88   - }
89   -
90   - return this.threadLocalContextual.get();
91   - }
92 81 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/BeanStore.java
1 1 package br.gov.frameworkdemoiselle.internal.context;
2 2  
3 3 import java.io.Serializable;
4   -import java.util.Collections;
5   -import java.util.HashMap;
6 4 import java.util.Iterator;
7   -import java.util.Map;
  5 +import java.util.concurrent.ConcurrentHashMap;
  6 +import java.util.concurrent.ConcurrentMap;
8 7  
9 8 import javax.enterprise.context.spi.CreationalContext;
10 9  
... ... @@ -13,14 +12,12 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable {
13 12  
14 13 private static final long serialVersionUID = 1L;
15 14  
16   - private Map<String, Object> instanceCache = Collections.synchronizedMap( new HashMap<String, Object>() );
17   - private Map<String, CreationalContext> creationalCache = Collections.synchronizedMap( new HashMap<String, CreationalContext>() );;
  15 + private ConcurrentMap<String, Object> instanceCache = new ConcurrentHashMap<String, Object>();
  16 + private ConcurrentMap<String, CreationalContext> creationalCache = new ConcurrentHashMap<String, CreationalContext>();
18 17  
19 18 public <T> void put(String id, T instance,CreationalContext<T> creationalContext){
20   - if (!instanceCache.containsKey(id)){
21   - instanceCache.put(id, instance);
22   - creationalCache.put(id, creationalContext);
23   - }
  19 + instanceCache.putIfAbsent(id, instance);
  20 + creationalCache.putIfAbsent(id, creationalContext);
24 21 }
25 22  
26 23 public Object getInstance(String id){
... ... @@ -44,5 +41,4 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable {
44 41 public Iterator<String> iterator() {
45 42 return instanceCache.keySet().iterator();
46 43 }
47   -
48 44 }
... ...
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java
1 1 package br.gov.frameworkdemoiselle.internal.context;
2 2  
3 3 import java.io.Serializable;
4   -import java.util.HashMap;
  4 +import java.util.concurrent.ConcurrentHashMap;
  5 +import java.util.concurrent.ConcurrentMap;
5 6 import java.util.concurrent.atomic.AtomicInteger;
6 7  
7 8 import javax.enterprise.context.spi.Contextual;
... ... @@ -15,46 +16,75 @@ public class ContextualStore implements Serializable {
15 16  
16 17 private static final String PREFIX = ContextualStore.class.getCanonicalName() + "#";
17 18  
18   - private AtomicInteger idGenerator = new AtomicInteger();
  19 + private final AtomicInteger idGenerator = new AtomicInteger();
19 20  
20   - private HashMap<String, Contextual> idToContextual = new HashMap<String, Contextual>();
21   -
22   - private HashMap<Contextual, String> contextualToId = new HashMap<Contextual, String>();
  21 + /*
  22 + * BASEADO NA IMPLEMENTAÇÃO DE CDI DO WELD
  23 + *
  24 + * Contextuals (instâncias de Bean) implementam a interface PassivationCapable quando são capazes
  25 + * de participar em um cluster de servidores, dessa forma o mesmo Bean pode ser usado para criar instâncias
  26 + * em todos os servidores e o ciclo de vida é síncrono
  27 + *
  28 + * Se o contextual não implementar PassivationCapable esse suporte não é possível. Por isso o WELD armazena
  29 + * separadamente contextuals que implementam PassivationCapable e que não implementam.
  30 + *
  31 + * A implementação abaixo foi baseada nesse comportamento, afim de evitar problemas em aplicações empacotadas em EAR
  32 + * e servidores de aplicação em cluster.
  33 + *
  34 + */
  35 + private final ConcurrentMap<String, Contextual> idToContextual = new ConcurrentHashMap<String, Contextual>();
  36 + private final ConcurrentMap<Contextual, String> contextualToId = new ConcurrentHashMap<Contextual, String>();
  37 + private final ConcurrentMap<String, Contextual> passivableIdToContextual = new ConcurrentHashMap<String, Contextual>();
23 38  
24 39 /**
25   - * The an unique ID for the given contextual. If it's the first time
  40 + * Return an unique ID for the given contextual. If it's the first time
26 41 * this contextual is accessed, registers the contextual for latter retrieval.
27 42 *
28 43 * @param contextual The contextual to generate an ID
29 44 * @return The unique ID for the contextual
30 45 */
31   - public String tryRegisterAndGetId(Contextual contextual){
  46 + public String putIfAbsentAndGetId(Contextual contextual){
32 47 String returnedId;
33 48  
34   - if (contextualToId.containsKey(contextual)){
35   - returnedId = contextualToId.get(contextual);
36   - }
37   - else if (contextual instanceof PassivationCapable){
  49 + if (contextual instanceof PassivationCapable){
38 50 returnedId = ((PassivationCapable)contextual).getId();
39   - idToContextual.put(returnedId, contextual);
40   - contextualToId.put(contextual, returnedId);
  51 + passivableIdToContextual.putIfAbsent(returnedId, contextual);
41 52 }
42 53 else{
43   - returnedId = PREFIX + idGenerator.addAndGet(1);
44   - idToContextual.put(returnedId, contextual);
45   - contextualToId.put(contextual, returnedId);
  54 + returnedId = contextualToId.get(contextual);
  55 + if (returnedId==null){
  56 + synchronized (contextual) {
  57 + //Esse código é uma implementação de performance. Se já existia
  58 + //ID para um contextual, retornamos. Do contrário precisamos fazer uma operação threadsafe
  59 + //que será cara. Então separamos a possibilide do ID já existir (a mais comum) fora do bloco
  60 + //synchronized, mas se precisarmos entrar no bloco precisamos perguntar pelo ID
  61 + //novamente, caso outra thread tenha criado o ID entre a primeira pergunta e a geração do ID.
  62 + returnedId = contextualToId.get(contextual);
  63 + if (returnedId==null){
  64 + returnedId = new StringBuffer().append(PREFIX).append(idGenerator.incrementAndGet()).toString();
  65 + idToContextual.put(returnedId, contextual);
  66 + contextualToId.put(contextual, returnedId);
  67 + }
  68 + }
  69 + }
46 70 }
47 71  
48 72 return returnedId;
49 73 }
50 74  
51 75 public Contextual getContextual(String id){
52   - return idToContextual.get(id);
  76 + if (id.startsWith(PREFIX)){
  77 + return idToContextual.get(id);
  78 + }
  79 + else{
  80 + return passivableIdToContextual.get(id);
  81 + }
53 82 }
54 83  
55 84 public void clear(){
56 85 idToContextual.clear();
57 86 contextualToId.clear();
  87 + passivableIdToContextual.clear();
58 88 }
59 89  
60 90 }
... ...
impl/core/src/main/resources/demoiselle-core-bundle.properties
... ... @@ -39,6 +39,7 @@ key-not-found=A chave {0} n\u00E3o foi encontrada
39 39 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.
40 40 ambiguous-bean-resolution=Falha ao obter {0} pois foi detectada ambiguidade nas seguintes implementa\u00E7\u00F5es\: {1}
41 41 bean-not-found=Voc\u00EA est\u00E1 tentando obter um objeto n\u00E3o reconhecido pelo CDI via Beans.getReference({0})
  42 +store-not-found=O objeto do tipo [{0}] n\u00E3o pode ser armazenado no escopo indicado\: {1}
42 43 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}
43 44 handling-exception=Tratando a exce\u00E7\u00E3o {0}
44 45 taking-off=O Demoiselle ${project.version} decolou
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/configuration/ViewScopeConfig.java 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +/*
  2 + * Demoiselle Framework
  3 + * Copyright (C) 2010 SERPRO
  4 + * ----------------------------------------------------------------------------
  5 + * This file is part of Demoiselle Framework.
  6 + *
  7 + * Demoiselle Framework is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU Lesser General Public License version 3
  9 + * as published by the Free Software Foundation.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public License version 3
  17 + * along with this program; if not, see <http://www.gnu.org/licenses/>
  18 + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
  19 + * Fifth Floor, Boston, MA 02110-1301, USA.
  20 + * ----------------------------------------------------------------------------
  21 + * Este arquivo é parte do Framework Demoiselle.
  22 + *
  23 + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou
  24 + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
  25 + * do Software Livre (FSF).
  26 + *
  27 + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
  28 + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
  29 + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
  30 + * para maiores detalhes.
  31 + *
  32 + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
  33 + * "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
  34 + * ou escreva para a Fundação do Software Livre (FSF) Inc.,
  35 + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
  36 + */
  37 +package br.gov.frameworkdemoiselle.internal.configuration;
  38 +
  39 +import java.io.Serializable;
  40 +
  41 +import br.gov.frameworkdemoiselle.annotation.Name;
  42 +import br.gov.frameworkdemoiselle.configuration.Configuration;
  43 +
  44 +@Configuration(prefix = "frameworkdemoiselle.scope.view")
  45 +public class ViewScopeConfig implements Serializable {
  46 +
  47 + private static final long serialVersionUID = 1L;
  48 +
  49 + @Name("timeout")
  50 + private int viewScopeTimeout = 1800;
  51 +
  52 + public int getViewScopeTimeout() {
  53 + return viewScopeTimeout;
  54 + }
  55 +
  56 + public void setViewScopeTimeout(int viewScopeTimeout) {
  57 + this.viewScopeTimeout = viewScopeTimeout;
  58 + }
  59 +}
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java
... ... @@ -36,11 +36,14 @@
36 36 */
37 37 package br.gov.frameworkdemoiselle.internal.context;
38 38  
39   -import java.util.Map;
  39 +import java.util.concurrent.ConcurrentHashMap;
  40 +import java.util.concurrent.atomic.AtomicLong;
40 41  
41 42 import javax.enterprise.inject.Alternative;
42 43 import javax.faces.component.UIViewRoot;
43 44 import javax.faces.context.FacesContext;
  45 +import javax.servlet.http.HttpServletRequest;
  46 +import javax.servlet.http.HttpSession;
44 47  
45 48 import br.gov.frameworkdemoiselle.annotation.Priority;
46 49 import br.gov.frameworkdemoiselle.annotation.ViewScoped;
... ... @@ -59,37 +62,80 @@ import br.gov.frameworkdemoiselle.util.Faces;
59 62 @Priority(Priority.L2_PRIORITY)
60 63 @Alternative
61 64 public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext {
62   -
  65 +
  66 + private final AtomicLong atomicLong = new AtomicLong();
  67 +
  68 + private ConcurrentHashMap<String, SessionBeanStore> sessionBeanStore = new ConcurrentHashMap<String, SessionBeanStore>();
  69 +
  70 + private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName();
  71 +
63 72 public FacesViewContextImpl() {
64 73 super(ViewScoped.class);
65 74 }
66 75  
67 76 @Override
68 77 protected boolean isStoreInitialized() {
69   - return FacesContext.getCurrentInstance()!=null;
  78 + return FacesContext.getCurrentInstance()!=null && getSessionId()!=null;
70 79 }
71 80  
72 81 @Override
73 82 protected BeanStore getStore() {
74   - Map<String, Object> viewMap = Faces.getViewMap();
75   - String key = BeanStore.class.getName();
76   -
77   - if (!viewMap.containsKey(key)) {
78   - viewMap.put(key, createStore());
  83 + clearInvalidatedSession();
  84 +
  85 + final String sessionId = getSessionId();
  86 +
  87 + if (sessionId==null){
  88 + return null;
  89 + }
  90 +
  91 + Long viewId = (Long)Faces.getViewMap().get(FACES_KEY);
  92 + if (viewId==null){
  93 + synchronized (this) {
  94 + viewId = (Long)Faces.getViewMap().get(FACES_KEY);
  95 + if (viewId==null){
  96 + viewId = atomicLong.incrementAndGet();
  97 + Faces.getViewMap().put(FACES_KEY, viewId);
  98 + }
  99 + }
79 100 }
80 101  
81   - return (BeanStore) viewMap.get(key);
  102 + SessionBeanStore currentStore = sessionBeanStore.get(sessionId);
  103 + if (currentStore==null){
  104 + synchronized (this) {
  105 + currentStore = (SessionBeanStore) sessionBeanStore.get(sessionId);
  106 + if (currentStore==null){
  107 + currentStore = new SessionBeanStore();
  108 + sessionBeanStore.put(sessionId, currentStore);
  109 + }
  110 + }
  111 + }
  112 +
  113 + return currentStore.getStore(viewId, this);
82 114 }
83   -
84   - @Override
85   - protected ContextualStore getContextualStore() {
86   - Map<String, Object> viewMap = Faces.getViewMap();
87   - String key = ContextualStore.class.getName();
88   -
89   - if (!viewMap.containsKey(key)) {
90   - viewMap.put(key, createContextualStore());
  115 +
  116 + private synchronized void clearInvalidatedSession(){
  117 + if (wasSessionInvalidated()){
  118 + final String requestedSessionId = getRequestedSessionId();
  119 + final SessionBeanStore store = sessionBeanStore.get(requestedSessionId);
  120 + if (store!=null){
  121 + store.clear(this);
  122 + sessionBeanStore.remove(requestedSessionId);
  123 + }
91 124 }
92   -
93   - return (ContextualStore) viewMap.get(key);
  125 + }
  126 +
  127 + private String getSessionId(){
  128 + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
  129 + return session!=null ? session.getId() : null;
  130 + }
  131 +
  132 + private String getRequestedSessionId(){
  133 + final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
  134 + return request!=null ? request.getRequestedSessionId() : null;
  135 + }
  136 +
  137 + private boolean wasSessionInvalidated(){
  138 + final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
  139 + return request!=null && request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid();
94 140 }
95 141 }
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/SessionBeanStore.java 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +package br.gov.frameworkdemoiselle.internal.context;
  2 +
  3 +import java.io.Serializable;
  4 +
  5 +import javax.enterprise.context.SessionScoped;
  6 +import javax.enterprise.context.spi.Contextual;
  7 +import javax.enterprise.context.spi.CreationalContext;
  8 +
  9 +@SessionScoped
  10 +public class SessionBeanStore implements Serializable {
  11 +
  12 + private static final long serialVersionUID = -8265458933971929432L;
  13 +
  14 + private Long lastViewId = null;
  15 +
  16 + private BeanStore store;
  17 +
  18 + synchronized BeanStore getStore(Long viewId, AbstractCustomContext context) {
  19 + if (lastViewId == null || !lastViewId.equals(viewId)) {
  20 + clear(context);
  21 + lastViewId = viewId;
  22 + store = AbstractCustomContext.createStore();
  23 + }
  24 +
  25 + return store;
  26 + }
  27 +
  28 + @SuppressWarnings({ "rawtypes", "unchecked" })
  29 + public void clear(AbstractCustomContext context) {
  30 + if (store != null) {
  31 + for (String id : store) {
  32 + Contextual contextual = context.getContextualStore().getContextual(id);
  33 + Object instance = store.getInstance(id);
  34 + CreationalContext creationalContext = store.getCreationalContext(id);
  35 +
  36 + if (contextual != null && instance != null) {
  37 + contextual.destroy(instance, creationalContext);
  38 + }
  39 + }
  40 + store.clear();
  41 + }
  42 + }
  43 +}
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Faces.java
... ... @@ -171,4 +171,9 @@ public class Faces {
171 171 UIViewRoot viewRoot = getFacesContext().getViewRoot();
172 172 return viewRoot.getViewMap(true);
173 173 }
  174 +
  175 + public static String getCurrentViewId(){
  176 + return getFacesContext().getViewRoot().getViewId();
  177 + }
  178 +
174 179 }
... ...