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,22 +130,22 @@ public abstract class AbstractLifecycleBootstrap<A extends Annotation> implement
130 ViewContext tempViewContext = Beans.getReference(ViewContext.class); 130 ViewContext tempViewContext = Beans.getReference(ViewContext.class);
131 ConversationContext tempConversationContext = Beans.getReference(ConversationContext.class); 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 if (!registered) { 138 if (!registered) {
139 - if (!tempRequestContext.isActive()) 139 + if (tempRequestContext!=null && !tempRequestContext.isActive())
140 tempRequestContext.activate(); 140 tempRequestContext.activate();
141 141
142 - if (!tempSessionContext.isActive()) 142 + if (tempSessionContext!=null && !tempSessionContext.isActive())
143 tempSessionContext.activate(); 143 tempSessionContext.activate();
144 144
145 - if (!tempViewContext.isActive()) 145 + if (tempViewContext!=null && !tempViewContext.isActive())
146 tempViewContext.activate(); 146 tempViewContext.activate();
147 147
148 - if (!tempConversationContext.isActive()) 148 + if (tempConversationContext!=null && !tempConversationContext.isActive())
149 tempConversationContext.activate(); 149 tempConversationContext.activate();
150 150
151 registered = true; 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 +10,11 @@ import javax.enterprise.inject.spi.ProcessAnnotatedType;
10 10
11 import br.gov.frameworkdemoiselle.context.CustomContext; 11 import br.gov.frameworkdemoiselle.context.CustomContext;
12 import br.gov.frameworkdemoiselle.context.StaticContext; 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 import br.gov.frameworkdemoiselle.internal.context.StaticContextImpl; 14 import br.gov.frameworkdemoiselle.internal.context.StaticContextImpl;
16 import br.gov.frameworkdemoiselle.internal.context.TemporaryConversationContextImpl; 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 import br.gov.frameworkdemoiselle.internal.context.TemporaryViewContextImpl; 18 import br.gov.frameworkdemoiselle.internal.context.TemporaryViewContextImpl;
18 import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess; 19 import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
19 20
@@ -28,6 +29,8 @@ public class CustomContextBootstrap implements Extension{ @@ -28,6 +29,8 @@ public class CustomContextBootstrap implements Extension{
28 29
29 private List<CustomContext> contexts; 30 private List<CustomContext> contexts;
30 31
  32 + private final ContextualStore contextualStore = new ContextualStore();
  33 +
31 public <T extends CustomContext> void vetoCustomContexts(@Observes ProcessAnnotatedType<T> event){ 34 public <T extends CustomContext> void vetoCustomContexts(@Observes ProcessAnnotatedType<T> event){
32 //Veta os subtipos de CustomContext, para que não conflitem com o produtor de contextos personalizados. 35 //Veta os subtipos de CustomContext, para que não conflitem com o produtor de contextos personalizados.
33 if( CustomContext.class.isAssignableFrom( event.getAnnotatedType().getJavaClass() )){ 36 if( CustomContext.class.isAssignableFrom( event.getAnnotatedType().getJavaClass() )){
@@ -79,10 +82,15 @@ public class CustomContextBootstrap implements Extension{ @@ -79,10 +82,15 @@ public class CustomContextBootstrap implements Extension{
79 } 82 }
80 83
81 contexts.clear(); 84 contexts.clear();
  85 + contextualStore.clear();
82 } 86 }
83 } 87 }
84 88
85 public List<CustomContext> getCustomContexts(){ 89 public List<CustomContext> getCustomContexts(){
86 return this.contexts; 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,11 +43,14 @@ import javax.enterprise.context.ContextNotActiveException;
43 import javax.enterprise.context.spi.Context; 43 import javax.enterprise.context.spi.Context;
44 import javax.enterprise.context.spi.Contextual; 44 import javax.enterprise.context.spi.Contextual;
45 import javax.enterprise.context.spi.CreationalContext; 45 import javax.enterprise.context.spi.CreationalContext;
  46 +import javax.enterprise.inject.spi.Bean;
46 import javax.enterprise.inject.spi.BeanManager; 47 import javax.enterprise.inject.spi.BeanManager;
47 48
48 import org.slf4j.Logger; 49 import org.slf4j.Logger;
49 50
  51 +import br.gov.frameworkdemoiselle.DemoiselleException;
50 import br.gov.frameworkdemoiselle.context.CustomContext; 52 import br.gov.frameworkdemoiselle.context.CustomContext;
  53 +import br.gov.frameworkdemoiselle.internal.bootstrap.CustomContextBootstrap;
51 import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer; 54 import br.gov.frameworkdemoiselle.internal.producer.LoggerProducer;
52 import br.gov.frameworkdemoiselle.util.Beans; 55 import br.gov.frameworkdemoiselle.util.Beans;
53 import br.gov.frameworkdemoiselle.util.ResourceBundle; 56 import br.gov.frameworkdemoiselle.util.ResourceBundle;
@@ -58,7 +61,7 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -58,7 +61,7 @@ public abstract class AbstractCustomContext implements CustomContext {
58 61
59 private final Class<? extends Annotation> scope; 62 private final Class<? extends Annotation> scope;
60 63
61 - private Logger logger; 64 + private transient Logger logger;
62 65
63 private transient ResourceBundle bundle; 66 private transient ResourceBundle bundle;
64 67
@@ -69,8 +72,6 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -69,8 +72,6 @@ public abstract class AbstractCustomContext implements CustomContext {
69 72
70 protected abstract BeanStore getStore(); 73 protected abstract BeanStore getStore();
71 74
72 - protected abstract ContextualStore getContextualStore();  
73 -  
74 protected abstract boolean isStoreInitialized(); 75 protected abstract boolean isStoreInitialized();
75 76
76 @Override 77 @Override
@@ -87,23 +88,24 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -87,23 +88,24 @@ public abstract class AbstractCustomContext implements CustomContext {
87 throw new ContextNotActiveException(); 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 return instance; 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 @Override 109 @Override
108 public boolean isActive() { 110 public boolean isActive() {
109 return this.active; 111 return this.active;
@@ -134,20 +136,11 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -134,20 +136,11 @@ public abstract class AbstractCustomContext implements CustomContext {
134 return this.active; 136 return this.active;
135 } 137 }
136 138
137 - @SuppressWarnings({ "rawtypes", "unchecked" })  
138 @Override 139 @Override
139 public void deactivate(){ 140 public void deactivate(){
140 if (this.active){ 141 if (this.active){
141 if (isStoreInitialized()){ 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 getStore().clear(); 145 getStore().clear();
153 getContextualStore().clear(); 146 getContextualStore().clear();
@@ -160,7 +153,23 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -160,7 +153,23 @@ public abstract class AbstractCustomContext implements CustomContext {
160 logger.debug( bundle.getString("custom-context-was-deactivated" , this.getClass().getCanonicalName() , this.getScope().getSimpleName() ) ); 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 @Override 173 @Override
165 public Class<? extends Annotation> getScope() { 174 public Class<? extends Annotation> getScope() {
166 return this.scope; 175 return this.scope;
@@ -190,6 +199,11 @@ public abstract class AbstractCustomContext implements CustomContext { @@ -190,6 +199,11 @@ public abstract class AbstractCustomContext implements CustomContext {
190 return logger; 199 return logger;
191 } 200 }
192 201
  202 + ContextualStore getContextualStore(){
  203 + CustomContextBootstrap bootstrap = Beans.getReference(CustomContextBootstrap.class);
  204 + return bootstrap.getContextualStore();
  205 + }
  206 +
193 @Override 207 @Override
194 public boolean equals(Object obj) { 208 public boolean equals(Object obj) {
195 if (this == obj) 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,8 +63,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext {
63 63
64 private final static Map<String, BeanStore> staticBeanStore = Collections.synchronizedMap(new HashMap<String, BeanStore>()); 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 * Constructs this context to control the provided scope 67 * Constructs this context to control the provided scope
70 */ 68 */
@@ -84,17 +82,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext { @@ -84,17 +82,6 @@ public abstract class AbstractStaticContext extends AbstractCustomContext {
84 } 82 }
85 83
86 @Override 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 protected boolean isStoreInitialized() { 85 protected boolean isStoreInitialized() {
99 return staticBeanStore!=null; 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,8 +61,6 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext {
61 61
62 private final ThreadLocal<BeanStore> threadLocalBeans = new ThreadLocal<BeanStore>(); 62 private final ThreadLocal<BeanStore> threadLocalBeans = new ThreadLocal<BeanStore>();
63 63
64 - private final ThreadLocal<ContextualStore> threadLocalContextual = new ThreadLocal<ContextualStore>();  
65 -  
66 AbstractThreadLocalContext(final Class<? extends Annotation> scope) { 64 AbstractThreadLocalContext(final Class<? extends Annotation> scope) {
67 super(scope); 65 super(scope);
68 } 66 }
@@ -80,13 +78,4 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext { @@ -80,13 +78,4 @@ public abstract class AbstractThreadLocalContext extends AbstractCustomContext {
80 78
81 return this.threadLocalBeans.get(); 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 package br.gov.frameworkdemoiselle.internal.context; 1 package br.gov.frameworkdemoiselle.internal.context;
2 2
3 import java.io.Serializable; 3 import java.io.Serializable;
4 -import java.util.Collections;  
5 -import java.util.HashMap;  
6 import java.util.Iterator; 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 import javax.enterprise.context.spi.CreationalContext; 8 import javax.enterprise.context.spi.CreationalContext;
10 9
@@ -13,14 +12,12 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable { @@ -13,14 +12,12 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable {
13 12
14 private static final long serialVersionUID = 1L; 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 public <T> void put(String id, T instance,CreationalContext<T> creationalContext){ 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 public Object getInstance(String id){ 23 public Object getInstance(String id){
@@ -44,5 +41,4 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable { @@ -44,5 +41,4 @@ public class BeanStore implements Iterable&lt;String&gt;,Serializable {
44 public Iterator<String> iterator() { 41 public Iterator<String> iterator() {
45 return instanceCache.keySet().iterator(); 42 return instanceCache.keySet().iterator();
46 } 43 }
47 -  
48 } 44 }
impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/context/ContextualStore.java
1 package br.gov.frameworkdemoiselle.internal.context; 1 package br.gov.frameworkdemoiselle.internal.context;
2 2
3 import java.io.Serializable; 3 import java.io.Serializable;
4 -import java.util.HashMap; 4 +import java.util.concurrent.ConcurrentHashMap;
  5 +import java.util.concurrent.ConcurrentMap;
5 import java.util.concurrent.atomic.AtomicInteger; 6 import java.util.concurrent.atomic.AtomicInteger;
6 7
7 import javax.enterprise.context.spi.Contextual; 8 import javax.enterprise.context.spi.Contextual;
@@ -15,46 +16,75 @@ public class ContextualStore implements Serializable { @@ -15,46 +16,75 @@ public class ContextualStore implements Serializable {
15 16
16 private static final String PREFIX = ContextualStore.class.getCanonicalName() + "#"; 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 * this contextual is accessed, registers the contextual for latter retrieval. 41 * this contextual is accessed, registers the contextual for latter retrieval.
27 * 42 *
28 * @param contextual The contextual to generate an ID 43 * @param contextual The contextual to generate an ID
29 * @return The unique ID for the contextual 44 * @return The unique ID for the contextual
30 */ 45 */
31 - public String tryRegisterAndGetId(Contextual contextual){ 46 + public String putIfAbsentAndGetId(Contextual contextual){
32 String returnedId; 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 returnedId = ((PassivationCapable)contextual).getId(); 50 returnedId = ((PassivationCapable)contextual).getId();
39 - idToContextual.put(returnedId, contextual);  
40 - contextualToId.put(contextual, returnedId); 51 + passivableIdToContextual.putIfAbsent(returnedId, contextual);
41 } 52 }
42 else{ 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 return returnedId; 72 return returnedId;
49 } 73 }
50 74
51 public Contextual getContextual(String id){ 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 public void clear(){ 84 public void clear(){
56 idToContextual.clear(); 85 idToContextual.clear();
57 contextualToId.clear(); 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,6 +39,7 @@ key-not-found=A chave {0} n\u00E3o foi encontrada
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. 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 ambiguous-bean-resolution=Falha ao obter {0} pois foi detectada ambiguidade nas seguintes implementa\u00E7\u00F5es\: {1} 40 ambiguous-bean-resolution=Falha ao obter {0} pois foi detectada ambiguidade nas seguintes implementa\u00E7\u00F5es\: {1}
41 bean-not-found=Voc\u00EA est\u00E1 tentando obter um objeto n\u00E3o reconhecido pelo CDI via Beans.getReference({0}) 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 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 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 handling-exception=Tratando a exce\u00E7\u00E3o {0} 44 handling-exception=Tratando a exce\u00E7\u00E3o {0}
44 taking-off=O Demoiselle ${project.version} decolou 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 @@ @@ -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,11 +36,14 @@
36 */ 36 */
37 package br.gov.frameworkdemoiselle.internal.context; 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 import javax.enterprise.inject.Alternative; 42 import javax.enterprise.inject.Alternative;
42 import javax.faces.component.UIViewRoot; 43 import javax.faces.component.UIViewRoot;
43 import javax.faces.context.FacesContext; 44 import javax.faces.context.FacesContext;
  45 +import javax.servlet.http.HttpServletRequest;
  46 +import javax.servlet.http.HttpSession;
44 47
45 import br.gov.frameworkdemoiselle.annotation.Priority; 48 import br.gov.frameworkdemoiselle.annotation.Priority;
46 import br.gov.frameworkdemoiselle.annotation.ViewScoped; 49 import br.gov.frameworkdemoiselle.annotation.ViewScoped;
@@ -59,37 +62,80 @@ import br.gov.frameworkdemoiselle.util.Faces; @@ -59,37 +62,80 @@ import br.gov.frameworkdemoiselle.util.Faces;
59 @Priority(Priority.L2_PRIORITY) 62 @Priority(Priority.L2_PRIORITY)
60 @Alternative 63 @Alternative
61 public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext { 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 public FacesViewContextImpl() { 72 public FacesViewContextImpl() {
64 super(ViewScoped.class); 73 super(ViewScoped.class);
65 } 74 }
66 75
67 @Override 76 @Override
68 protected boolean isStoreInitialized() { 77 protected boolean isStoreInitialized() {
69 - return FacesContext.getCurrentInstance()!=null; 78 + return FacesContext.getCurrentInstance()!=null && getSessionId()!=null;
70 } 79 }
71 80
72 @Override 81 @Override
73 protected BeanStore getStore() { 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 @@ @@ -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,4 +171,9 @@ public class Faces {
171 UIViewRoot viewRoot = getFacesContext().getViewRoot(); 171 UIViewRoot viewRoot = getFacesContext().getViewRoot();
172 return viewRoot.getViewMap(true); 172 return viewRoot.getViewMap(true);
173 } 173 }
  174 +
  175 + public static String getCurrentViewId(){
  176 + return getFacesContext().getViewRoot().getViewId();
  177 + }
  178 +
174 } 179 }