Commit 02b5874da1b080651ecfb6999845812934499d2f

Authored by Danilo Costa Viana
1 parent 0c349ba8
Exists in master

[FWK-232] Correção para problema de beans com escopo @ViewScoped sendo

imediatamente destruído ao trocar de visão, causando nova construção do
bean caso a visão antiga seja acessada após uma nova visão ser criada.
archetype/html-rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
@@ -15,6 +15,12 @@ @@ -15,6 +15,12 @@
15 <listener> 15 <listener>
16 <listener-class>br.gov.frameworkdemoiselle.util.ServletListener</listener-class> 16 <listener-class>br.gov.frameworkdemoiselle.util.ServletListener</listener-class>
17 </listener> 17 </listener>
  18 + <listener>
  19 + <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class>
  20 + </listener>
  21 + <listener>
  22 + <listener-class>br.gov.frameworkdemoiselle.util.RequestListener</listener-class>
  23 + </listener>
18 <filter> 24 <filter>
19 <filter-name>Demoiselle Servlet Filter</filter-name> 25 <filter-name>Demoiselle Servlet Filter</filter-name>
20 <filter-class>br.gov.frameworkdemoiselle.util.ServletFilter</filter-class> 26 <filter-class>br.gov.frameworkdemoiselle.util.ServletFilter</filter-class>
archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
@@ -21,6 +21,9 @@ @@ -21,6 +21,9 @@
21 <listener> 21 <listener>
22 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class> 22 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class>
23 </listener> 23 </listener>
  24 + <listener>
  25 + <listener-class>br.gov.frameworkdemoiselle.util.RequestListener</listener-class>
  26 + </listener>
24 <filter> 27 <filter>
25 <filter-name>Demoiselle Servlet Filter</filter-name> 28 <filter-name>Demoiselle Servlet Filter</filter-name>
26 <filter-class>br.gov.frameworkdemoiselle.util.ServletFilter</filter-class> 29 <filter-class>br.gov.frameworkdemoiselle.util.ServletFilter</filter-class>
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java
@@ -48,14 +48,11 @@ import br.gov.frameworkdemoiselle.util.Beans; @@ -48,14 +48,11 @@ import br.gov.frameworkdemoiselle.util.Beans;
48 48
49 public class JsfBootstrap implements Extension { 49 public class JsfBootstrap implements Extension {
50 50
51 - //private List<CustomContext> customContexts = new ArrayList<CustomContext>();  
52 -  
53 - //private AfterBeanDiscovery afterBeanDiscoveryEvent;  
54 -  
55 private FacesViewContextImpl context; 51 private FacesViewContextImpl context;
  52 +
56 private boolean contextActivatedHere; 53 private boolean contextActivatedHere;
57 -  
58 - public void createCustomContext(@Observes AfterBeanDiscovery event){ 54 +
  55 + public void createCustomContext(@Observes AfterBeanDiscovery event) {
59 context = new FacesViewContextImpl(); 56 context = new FacesViewContextImpl();
60 event.addContext(context); 57 event.addContext(context);
61 } 58 }
@@ -63,19 +60,18 @@ public class JsfBootstrap implements Extension { @@ -63,19 +60,18 @@ public class JsfBootstrap implements Extension {
63 public void addContexts(@Observes final AfterDeploymentValidation event) { 60 public void addContexts(@Observes final AfterDeploymentValidation event) {
64 CustomContextProducer producer = Beans.getReference(CustomContextProducer.class); 61 CustomContextProducer producer = Beans.getReference(CustomContextProducer.class);
65 producer.addRegisteredContext(context); 62 producer.addRegisteredContext(context);
66 -  
67 - //Ativa o ViewContext  
68 - if (!context.isActive()){ 63 +
  64 + // Ativa o ViewContext
  65 + if (!context.isActive()) {
69 contextActivatedHere = context.activate(); 66 contextActivatedHere = context.activate();
70 - }  
71 - else{ 67 + } else {
72 contextActivatedHere = false; 68 contextActivatedHere = false;
73 } 69 }
74 } 70 }
75 71
76 public void removeContexts(@Observes AfterShutdownProccess event) { 72 public void removeContexts(@Observes AfterShutdownProccess event) {
77 - //Desativa o ViewContext  
78 - if (contextActivatedHere){ 73 + // Desativa o ViewContext
  74 + if (contextActivatedHere) {
79 context.deactivate(); 75 context.deactivate();
80 } 76 }
81 } 77 }
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.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.Iterator;
  5 +import java.util.Map.Entry;
  6 +import java.util.concurrent.ConcurrentHashMap;
4 7
5 import javax.enterprise.context.spi.Contextual; 8 import javax.enterprise.context.spi.Contextual;
6 import javax.enterprise.context.spi.CreationalContext; 9 import javax.enterprise.context.spi.CreationalContext;
7 -import javax.enterprise.inject.Alternative; 10 +
  11 +import br.gov.frameworkdemoiselle.context.ViewContext;
  12 +import br.gov.frameworkdemoiselle.util.ResourceBundle;
8 13
9 /** 14 /**
10 - * Store that keeps view scoped beans. It associates all view scoped beans with a view ID.  
11 - * When the ID changes (meaning the view changed) all old view scoped beans are destroyed  
12 - * before new beans for the new view are created and stored. 15 + * Store that keeps view scoped beans. It associates all view scoped beans with a view ID. When the ID changes (meaning
  16 + * the view changed) all old view scoped beans are destroyed before new beans for the new view are created and stored.
13 * 17 *
14 * @author SERPRO 18 * @author SERPRO
15 - *  
16 */ 19 */
17 -@Alternative  
18 public class FacesViewBeanStore implements Serializable { 20 public class FacesViewBeanStore implements Serializable {
19 21
20 private static final long serialVersionUID = -8265458933971929432L; 22 private static final long serialVersionUID = -8265458933971929432L;
21 23
22 - private Long lastViewId = null; 24 + private final ConcurrentHashMap<Long, FacesViewData> viewStore = new ConcurrentHashMap<Long, FacesViewBeanStore.FacesViewData>();
  25 +
  26 + private long maxInactiveTimeInSeconds;
23 27
24 - private BeanStore store; 28 + public FacesViewBeanStore(long maxInactiveTimeInSeconds) {
  29 + this.maxInactiveTimeInSeconds = maxInactiveTimeInSeconds;
  30 + }
25 31
26 - synchronized BeanStore getStore(Long viewId, AbstractCustomContext context) {  
27 - if (lastViewId == null || !lastViewId.equals(viewId)) {  
28 - clear(context);  
29 - lastViewId = viewId;  
30 - store = AbstractCustomContext.createStore(); 32 + /**
  33 + * Gets the store that contains the view scoped beans for that view ID. If no store exists (new view) one is
  34 + * created.
  35 + *
  36 + * @param viewId
  37 + * ID of the current view
  38 + * @param context
  39 + * Reference to the {@link ViewContext} class managing the view scope
  40 + * @return The {@link BeanStore} that stores view scoped beans for this view ID
  41 + * @throws IllegalStateException
  42 + * if the view associated with the requested view ID has expired
  43 + */
  44 + public BeanStore getStoreForView(Long viewId, AbstractCustomContext context) {
  45 + FacesViewData data = null;
  46 + synchronized (viewStore) {
  47 + data = viewStore.get(viewId);
  48 + if (data == null) {
  49 + BeanStore store = AbstractCustomContext.createStore();
  50 + data = new FacesViewData();
  51 + data.store = store;
  52 + viewStore.put(viewId, data);
  53 + } else if (data.isExpired(maxInactiveTimeInSeconds)) {
  54 + throw new IllegalStateException(ResourceBundle.getBundle("demoiselle-jsf-bundle").getString(
  55 + "view-expired"));
  56 + }
31 } 57 }
32 58
33 - return store; 59 + data.lastTimeAccessed = System.currentTimeMillis();
  60 + return data.store;
34 } 61 }
35 62
  63 + /**
  64 + * @see #destroyStoresInSession(AbstractCustomContext, boolean)
  65 + */
  66 + public void destroyStoresInSession(AbstractCustomContext context) {
  67 + destroyStoresInSession(context, false);
  68 + }
  69 +
  70 + /**
  71 + * Destroys all View scoped beans and the associated {@link BeanStore} for this user's session. The destroyed beans
  72 + * will respect CDI bean lifecycle, thus they'll trigger any events associated with destroying beans.
  73 + *
  74 + * @param context
  75 + * ViewContext managing the view scoped beans
  76 + * @param onlyExpired
  77 + * Only destroy beans if the underlying view has expired
  78 + */
36 @SuppressWarnings({ "rawtypes", "unchecked" }) 79 @SuppressWarnings({ "rawtypes", "unchecked" })
37 - public void clear(AbstractCustomContext context) {  
38 - if (store != null) {  
39 - for (String id : store) {  
40 - Contextual contextual = context.getContextualStore().getContextual(id);  
41 - Object instance = store.getInstance(id);  
42 - CreationalContext creationalContext = store.getCreationalContext(id);  
43 -  
44 - if (contextual != null && instance != null) {  
45 - contextual.destroy(instance, creationalContext); 80 + public void destroyStoresInSession(final AbstractCustomContext context, final boolean onlyExpired) {
  81 + for (Iterator<Entry<Long, FacesViewData>> it = viewStore.entrySet().iterator(); it.hasNext();) {
  82 + Entry<Long, FacesViewData> currentEntry = it.next();
  83 + FacesViewData data = currentEntry.getValue();
  84 +
  85 + if (data != null && data.store != null) {
  86 + if (!onlyExpired || data.isExpired(maxInactiveTimeInSeconds)) {
  87 + for (String id : data.store) {
  88 + Contextual contextual = context.getContextualStore().getContextual(id);
  89 + Object instance = data.store.getInstance(id);
  90 + CreationalContext creationalContext = data.store.getCreationalContext(id);
  91 +
  92 + if (contextual != null && instance != null) {
  93 + contextual.destroy(instance, creationalContext);
  94 + }
  95 + }
  96 +
  97 + data.store.clear();
  98 + it.remove();
46 } 99 }
47 } 100 }
48 - store.clear(); 101 + }
  102 + }
  103 +
  104 + /**
  105 + * Contains a {@link BeanStore} with some metadata, like the last time this store was accessed (used to determine
  106 + * when a store expires).
  107 + *
  108 + * @author serpro
  109 + */
  110 + private static class FacesViewData {
  111 +
  112 + long lastTimeAccessed;
  113 +
  114 + BeanStore store;
  115 +
  116 + public synchronized boolean isExpired(long viewTimeoutInSeconds) {
  117 + return ((System.currentTimeMillis() - lastTimeAccessed) / 1000) > viewTimeoutInSeconds;
49 } 118 }
50 } 119 }
51 } 120 }
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java
@@ -46,133 +46,193 @@ import javax.enterprise.event.Observes; @@ -46,133 +46,193 @@ import javax.enterprise.event.Observes;
46 import javax.enterprise.inject.Alternative; 46 import javax.enterprise.inject.Alternative;
47 import javax.faces.component.UIViewRoot; 47 import javax.faces.component.UIViewRoot;
48 import javax.faces.context.FacesContext; 48 import javax.faces.context.FacesContext;
  49 +import javax.servlet.ServletRequest;
  50 +import javax.servlet.http.HttpServletRequest;
49 import javax.servlet.http.HttpSession; 51 import javax.servlet.http.HttpSession;
50 52
51 import br.gov.frameworkdemoiselle.annotation.Priority; 53 import br.gov.frameworkdemoiselle.annotation.Priority;
52 import br.gov.frameworkdemoiselle.context.ViewContext; 54 import br.gov.frameworkdemoiselle.context.ViewContext;
  55 +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestDestroyed;
53 import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed; 56 import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed;
54 import br.gov.frameworkdemoiselle.lifecycle.ViewScoped; 57 import br.gov.frameworkdemoiselle.lifecycle.ViewScoped;
55 import br.gov.frameworkdemoiselle.util.Beans; 58 import br.gov.frameworkdemoiselle.util.Beans;
56 import br.gov.frameworkdemoiselle.util.Faces; 59 import br.gov.frameworkdemoiselle.util.Faces;
57 60
58 /** 61 /**
59 - *  
60 - * This {@link ViewContext} implementation uses a map provided  
61 - * by {@link UIViewRoot#getViewMap()} as a store. Any beans stored on  
62 - * this store are kept as long as the view is still active. 62 + * This {@link ViewContext} implementation uses a map provided by {@link UIViewRoot#getViewMap()} as a store. Any beans
  63 + * stored on this store are kept as long as the view is still active.
63 * 64 *
64 * @author serpro 65 * @author serpro
65 - *  
66 */ 66 */
67 @Priority(Priority.L2_PRIORITY) 67 @Priority(Priority.L2_PRIORITY)
68 @Alternative 68 @Alternative
69 public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext { 69 public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext {
70 - 70 +
71 private final AtomicLong atomicLong = new AtomicLong(); 71 private final AtomicLong atomicLong = new AtomicLong();
72 -  
73 - private ConcurrentHashMap<String, FacesViewBeanStore> sessionBeanStore = new ConcurrentHashMap<String, FacesViewBeanStore>();  
74 - 72 +
  73 + // Armazena todas as views relacionadas à sessão atual. Quando uma sessão
  74 + // termina, o store correspondente é destruído.
  75 + private ConcurrentHashMap<String, FacesViewBeanStore> viewStoreInSession = new ConcurrentHashMap<String, FacesViewBeanStore>();
  76 +
75 private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName(); 77 private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName();
76 - 78 +
77 public FacesViewContextImpl() { 79 public FacesViewContextImpl() {
78 super(ViewScoped.class); 80 super(ViewScoped.class);
79 } 81 }
80 - 82 +
81 @Override 83 @Override
82 protected boolean isStoreInitialized() { 84 protected boolean isStoreInitialized() {
83 - return FacesContext.getCurrentInstance()!=null && getSessionId()!=null; 85 + return FacesContext.getCurrentInstance() != null && getSessionId() != null;
84 } 86 }
85 87
86 @Override 88 @Override
87 protected BeanStore getStore() { 89 protected BeanStore getStore() {
88 String sessionId = getSessionId(); 90 String sessionId = getSessionId();
89 - if (sessionId == null){ 91 + if (sessionId == null) {
90 return null; 92 return null;
91 } 93 }
92 - 94 +
93 /* 95 /*
94 - * Tenta obter o viewID de forma não thread-safe por questões de performance.  
95 - * Se o viewID não existe entra em um trecho thread-safe para incrementa-lo, evitando  
96 - * conflito entre duas requests tentando incrementar esse número. 96 + * Tenta obter o viewID de forma não thread-safe por questões de performance. Se o viewID não existe entra em um
  97 + * trecho thread-safe para incrementa-lo, evitando conflito entre duas requests tentando incrementar esse
  98 + * número.
97 */ 99 */
98 - Long viewId = (Long)Faces.getViewMap().get(FACES_KEY);  
99 - if (viewId==null){ 100 + Long viewId = (Long) Faces.getViewMap().get(FACES_KEY);
  101 + if (viewId == null) {
100 synchronized (this) { 102 synchronized (this) {
101 -  
102 - //Tenta obte-lo novamente, caso entre a primeira tentativa e o bloqueio  
103 - //da thread outra thread já tenha criado o número.  
104 - viewId = (Long)Faces.getViewMap().get(FACES_KEY);  
105 - if (viewId==null){ 103 +
  104 + // Tenta obte-lo novamente, caso entre a primeira tentativa e o
  105 + // bloqueio
  106 + // da thread outra thread já tenha criado o número.
  107 + viewId = (Long) Faces.getViewMap().get(FACES_KEY);
  108 + if (viewId == null) {
106 viewId = atomicLong.incrementAndGet(); 109 viewId = atomicLong.incrementAndGet();
107 Faces.getViewMap().put(FACES_KEY, viewId); 110 Faces.getViewMap().put(FACES_KEY, viewId);
108 } 111 }
109 } 112 }
110 } 113 }
111 114
112 - //A mesma técnica de bloqueio de thread acima é usada aqui para  
113 - //criar um SessionBeanStore caso o mesmo ainda não exista.  
114 - FacesViewBeanStore currentStore = sessionBeanStore.get(sessionId);  
115 - if (currentStore==null){ 115 + // A mesma técnica de bloqueio de thread acima é usada aqui para
  116 + // criar um FacesViewBeanStore caso o mesmo ainda não exista, e
  117 + // associa-lo à sessão atual.
  118 + FacesViewBeanStore currentViewStore = viewStoreInSession.get(sessionId);
  119 + if (currentViewStore == null) {
116 synchronized (this) { 120 synchronized (this) {
117 - currentStore = (FacesViewBeanStore) sessionBeanStore.get(sessionId);  
118 - if (currentStore==null){  
119 - currentStore = new FacesViewBeanStore();  
120 - sessionBeanStore.put(sessionId, currentStore); 121 + currentViewStore = (FacesViewBeanStore) viewStoreInSession.get(sessionId);
  122 + if (currentViewStore == null) {
  123 + currentViewStore = new FacesViewBeanStore(getSessionTimeout());
  124 + viewStoreInSession.put(sessionId, currentViewStore);
121 } 125 }
122 } 126 }
123 } 127 }
124 128
125 - return currentStore.getStore(viewId, this); 129 + return currentViewStore.getStoreForView(viewId, this);
126 } 130 }
127 - 131 +
128 /* 132 /*
129 * Called before the session is invalidated for that user. 133 * Called before the session is invalidated for that user.
130 * Destroys all view scoped beans stored on that session. 134 * Destroys all view scoped beans stored on that session.
131 */ 135 */
132 - private void clearInvalidatedSession(String sessionId){  
133 - if (sessionId != null){  
134 - final FacesViewBeanStore store = sessionBeanStore.get(sessionId);  
135 - if (store!=null){  
136 - store.clear(this);  
137 - sessionBeanStore.remove(sessionId); 136 + private void clearInvalidatedSession(String sessionId) {
  137 + if (sessionId != null) {
  138 + final FacesViewBeanStore store = viewStoreInSession.get(sessionId);
  139 + if (store != null) {
  140 + store.destroyStoresInSession(this);
  141 + viewStoreInSession.remove(sessionId);
  142 + }
  143 + }
  144 + }
  145 +
  146 + /*
  147 + * Called at each new request at a given session.
  148 + * Destroys any expired views.
  149 + */
  150 + private synchronized void clearExpiredViews(String sessionId) {
  151 + if (sessionId != null) {
  152 + final FacesViewBeanStore store = viewStoreInSession.get(sessionId);
  153 + if (store != null) {
  154 + store.destroyStoresInSession(this, true);
138 } 155 }
139 } 156 }
140 } 157 }
141 - 158 +
  159 + /*
  160 + * Returns the current session ID. Creates a session if one doesn't exist.
  161 + * Returns NULL if the session can't be created.
  162 + */
  163 + private String getSessionId() {
  164 + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext()
  165 + .getSession(true);
  166 + return session != null ? session.getId() : null;
  167 + }
  168 +
142 /* 169 /*
143 - * Returns the current session ID. Creates a session if one doesn't exist. Returns NULL if the session can't be created. 170 + * Returns the configured session timeout in seconds. This is the maximum
  171 + * inactive interval, not the remaining timeout for this session.
144 */ 172 */
145 - private String getSessionId(){  
146 - final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);  
147 - return session!=null ? session.getId() : null; 173 + private int getSessionTimeout() {
  174 + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext()
  175 + .getSession(true);
  176 + return session != null ? session.getMaxInactiveInterval() : 0;
148 } 177 }
149 - 178 +
150 /** 179 /**
151 - * Observes HTTP session lifecycle and notifies the ViewContext of session events (creation or destruction)  
152 - * so view scoped beans can be created or destroyed based on their underlying session scopes. 180 + * Observes HTTP servlet lifecycle and notifies the ViewContext of session events (creation or destruction)
  181 + * and request events (before going into scope and before going out of scope) so view
  182 + * scoped beans can be created or destroyed based on their underlying session and request scopes.
153 * 183 *
154 * @author SERPRO 184 * @author SERPRO
155 - *  
156 */ 185 */
157 @ApplicationScoped 186 @ApplicationScoped
158 - protected static class FacesViewSessionListener {  
159 - 187 + protected static class ServletEventListener {
  188 +
160 /** 189 /**
161 - * Called before the session is invalidated for that user.  
162 - * Destroys all view scoped beans stored on that session. 190 + * Called before the session is invalidated for that user. Destroys all view scoped beans stored on that
  191 + * session.
163 */ 192 */
164 - protected void clearInvalidatedSession(@Observes BeforeSessionDestroyed event){ 193 + protected void clearInvalidatedSession(@Observes BeforeSessionDestroyed event) {
165 String sessionId = event.getSessionId(); 194 String sessionId = event.getSessionId();
166 - try{ 195 + try {
167 Context context = Beans.getBeanManager().getContext(ViewScoped.class); 196 Context context = Beans.getBeanManager().getContext(ViewScoped.class);
168 - if ( FacesViewContextImpl.class.isInstance(context) ){  
169 - ((FacesViewContextImpl)context).clearInvalidatedSession(sessionId); 197 + if (FacesViewContextImpl.class.isInstance(context)) {
  198 + ((FacesViewContextImpl) context).clearInvalidatedSession(sessionId);
170 } 199 }
  200 + } catch (ContextNotActiveException ce) {
  201 + // Nada a fazer, contexto não está ativo.
171 } 202 }
172 - catch(ContextNotActiveException ce){  
173 - //Nada a fazer, contexto não está ativo. 203 + }
  204 +
  205 + /**
  206 + * Called before the current request is about to go out of scope. Checks if any currently
  207 + * active views have expired and requests the destruction of those beans according to CDI
  208 + * lifecycle.
  209 + *
  210 + */
  211 + protected void clearExpiredViews(@Observes BeforeRequestDestroyed event) {
  212 + ServletRequest request = event.getRequest();
  213 +
  214 + if (HttpServletRequest.class.isInstance(request)) {
  215 + HttpSession session = ((HttpServletRequest) request).getSession(false);
  216 +
  217 + if (session != null) {
  218 + try {
  219 + final Context context = Beans.getBeanManager().getContext(ViewScoped.class);
  220 + final String currentSessionId = session.getId();
  221 +
  222 + if (FacesViewContextImpl.class.isInstance(context)) {
  223 + new Thread() {
  224 +
  225 + @Override
  226 + public void run() {
  227 + ((FacesViewContextImpl) context).clearExpiredViews(currentSessionId);
  228 + }
  229 + }.start();
  230 + }
  231 + } catch (ContextNotActiveException ce) {
  232 + // Nada a fazer, contexto não está ativo.
  233 + }
  234 + }
174 } 235 }
175 } 236 }
176 } 237 }
177 } 238 }
178 -  
impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties
@@ -37,4 +37,5 @@ id-converter-not-found=Voc\u00EA precisa criar um FacesConverter para a classe &quot; @@ -37,4 +37,5 @@ id-converter-not-found=Voc\u00EA precisa criar um FacesConverter para a classe &quot;
37 login-page-not-found=A tela de login "{0}" n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.login.page" 37 login-page-not-found=A tela de login "{0}" n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.login.page"
38 after-login-page-not-found=A tela "{0}" acessada ap\u00F3s o login n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.redirect.after.login" 38 after-login-page-not-found=A tela "{0}" acessada ap\u00F3s o login n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.redirect.after.login"
39 after-logout-page-not-found=A tela "{0}" acessada ap\u00F3s o logout n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.redirect.after.logout" 39 after-logout-page-not-found=A tela "{0}" acessada ap\u00F3s o logout n\u00E3o foi encontrada. Caso essa n\u00E3o seja a p\u00E1gina correta, defina a p\u00E1gina no arquivo de configura\u00E7\u00E3o usando a chave "frameworkdemoiselle.security.redirect.after.logout"
40 -faces-context-not-available=N\u00E3o existe uma inst\u00E2ncia de FacesContext ativa para esse escopo  
41 \ No newline at end of file 40 \ No newline at end of file
  41 +faces-context-not-available=N\u00E3o existe uma inst\u00E2ncia de FacesContext ativa para esse escopo
  42 +view-expired=A vis\u00E3o referenciada por essa tela expirou.
42 \ No newline at end of file 43 \ No newline at end of file
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java
  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 + */
1 package br.gov.frameworkdemoiselle.lifecycle; 37 package br.gov.frameworkdemoiselle.lifecycle;
2 38
3 /** 39 /**
4 * This interface represents an event fired after a new HTTP session is created. 40 * This interface represents an event fired after a new HTTP session is created.
5 * 41 *
6 * @author serpro 42 * @author serpro
7 - *  
8 */ 43 */
9 public interface AfterSessionCreated { 44 public interface AfterSessionCreated {
10 - 45 +
11 /** 46 /**
12 - *  
13 * @return The ID of the recently created session 47 * @return The ID of the recently created session
14 */ 48 */
15 public String getSessionId(); 49 public String getSessionId();
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java 0 → 100644
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  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.lifecycle;
  38 +
  39 +import javax.servlet.ServletContext;
  40 +import javax.servlet.ServletRequest;
  41 +
  42 +/**
  43 + * Event fired just before a request is about to go out of scope
  44 + *
  45 + * @author serpro
  46 + */
  47 +public interface BeforeRequestDestroyed {
  48 +
  49 + public ServletRequest getRequest();
  50 +
  51 + public ServletContext getServletContext();
  52 +
  53 +}
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java 0 → 100644
@@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
  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.lifecycle;
  38 +
  39 +import javax.servlet.ServletContext;
  40 +import javax.servlet.ServletRequest;
  41 +
  42 +/**
  43 + * Event fired just before a request is about to come into scope.
  44 + *
  45 + * @author serpro
  46 + *
  47 + */
  48 +public interface BeforeRequestInitialized {
  49 +
  50 + public ServletRequest getRequest();
  51 +
  52 + public ServletContext getServletContext();
  53 +
  54 +}
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java
  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 + */
1 package br.gov.frameworkdemoiselle.lifecycle; 37 package br.gov.frameworkdemoiselle.lifecycle;
2 38
3 /** 39 /**
4 * This interface represents an event fired before an HTTP session is destroyed. 40 * This interface represents an event fired before an HTTP session is destroyed.
5 * 41 *
6 * @author serpro 42 * @author serpro
7 - *  
8 */ 43 */
9 public interface BeforeSessionDestroyed { 44 public interface BeforeSessionDestroyed {
10 - 45 +
11 /** 46 /**
12 - *  
13 * @return The session ID of the session about to be destroyed 47 * @return The session ID of the session about to be destroyed
14 */ 48 */
15 public String getSessionId(); 49 public String getSessionId();
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java 0 → 100644
@@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
  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.util;
  38 +
  39 +import javax.servlet.ServletContext;
  40 +import javax.servlet.ServletRequest;
  41 +import javax.servlet.ServletRequestEvent;
  42 +import javax.servlet.ServletRequestListener;
  43 +import javax.servlet.annotation.WebListener;
  44 +
  45 +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestDestroyed;
  46 +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestInitialized;
  47 +
  48 +/**
  49 + * <p>
  50 + * Implements the {@link javax.servlet.ServletRequestListener} interface and fires two events.
  51 + * </p>
  52 + * <ul>
  53 + * <li><strong>{@link BeforeRequestInitialized}</strong>: Just before a new HTTP request comes into scope</li>
  54 + * <li><strong>{@link BeforeRequestDestroyed}</strong>: Just before an HTTP request will go out of scope</li>
  55 + * </ul>
  56 + *
  57 + * @author serpro
  58 + */
  59 +@WebListener
  60 +public class RequestListener implements ServletRequestListener {
  61 +
  62 + @Override
  63 + public void requestDestroyed(final ServletRequestEvent sre) {
  64 + Beans.getBeanManager().fireEvent(new BeforeRequestDestroyed() {
  65 +
  66 + @Override
  67 + public ServletRequest getRequest() {
  68 + return sre.getServletRequest();
  69 + }
  70 +
  71 + @Override
  72 + public ServletContext getServletContext() {
  73 + return sre.getServletContext();
  74 + }
  75 + });
  76 + }
  77 +
  78 + @Override
  79 + public void requestInitialized(final ServletRequestEvent sre) {
  80 + Beans.getBeanManager().fireEvent(new BeforeRequestDestroyed() {
  81 +
  82 + @Override
  83 + public ServletRequest getRequest() {
  84 + return sre.getServletRequest();
  85 + }
  86 +
  87 + @Override
  88 + public ServletContext getServletContext() {
  89 + return sre.getServletContext();
  90 + }
  91 + });
  92 + }
  93 +
  94 +}
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java
  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 + */
1 package br.gov.frameworkdemoiselle.util; 37 package br.gov.frameworkdemoiselle.util;
2 38
  39 +import javax.servlet.annotation.WebListener;
3 import javax.servlet.http.HttpSession; 40 import javax.servlet.http.HttpSession;
4 import javax.servlet.http.HttpSessionEvent; 41 import javax.servlet.http.HttpSessionEvent;
5 import javax.servlet.http.HttpSessionListener; 42 import javax.servlet.http.HttpSessionListener;
@@ -8,25 +45,27 @@ import br.gov.frameworkdemoiselle.lifecycle.AfterSessionCreated; @@ -8,25 +45,27 @@ import br.gov.frameworkdemoiselle.lifecycle.AfterSessionCreated;
8 import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed; 45 import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed;
9 46
10 /** 47 /**
11 - * <p>Implements the {@link HttpSessionListener} interface and fires two events.</p>  
12 - * 48 + * <p>
  49 + * Implements the {@link HttpSessionListener} interface and fires two events.
  50 + * </p>
13 * <ul> 51 * <ul>
14 * <li><strong>{@link AfterSessionCreated}</strong>: Just after a new HTTP session is created</li> 52 * <li><strong>{@link AfterSessionCreated}</strong>: Just after a new HTTP session is created</li>
15 * <li><strong>{@link BeforeSessionDestroyed}</strong>: Just before an HTTP session is invalidated</li> 53 * <li><strong>{@link BeforeSessionDestroyed}</strong>: Just before an HTTP session is invalidated</li>
16 * </ul> 54 * </ul>
17 * 55 *
18 * @author serpro 56 * @author serpro
19 - *  
20 */ 57 */
  58 +@WebListener
21 public class SessionListener implements HttpSessionListener { 59 public class SessionListener implements HttpSessionListener {
22 - 60 +
23 @Override 61 @Override
24 public void sessionCreated(final HttpSessionEvent sessionEvent) { 62 public void sessionCreated(final HttpSessionEvent sessionEvent) {
25 Beans.getBeanManager().fireEvent(new AfterSessionCreated() { 63 Beans.getBeanManager().fireEvent(new AfterSessionCreated() {
  64 +
26 @Override 65 @Override
27 public String getSessionId() { 66 public String getSessionId() {
28 HttpSession session = sessionEvent.getSession(); 67 HttpSession session = sessionEvent.getSession();
29 - return session!=null ? session.getId() : null; 68 + return session != null ? session.getId() : null;
30 } 69 }
31 }); 70 });
32 } 71 }
@@ -34,10 +73,11 @@ public class SessionListener implements HttpSessionListener { @@ -34,10 +73,11 @@ public class SessionListener implements HttpSessionListener {
34 @Override 73 @Override
35 public void sessionDestroyed(final HttpSessionEvent sessionEvent) { 74 public void sessionDestroyed(final HttpSessionEvent sessionEvent) {
36 Beans.getBeanManager().fireEvent(new BeforeSessionDestroyed() { 75 Beans.getBeanManager().fireEvent(new BeforeSessionDestroyed() {
  76 +
37 @Override 77 @Override
38 public String getSessionId() { 78 public String getSessionId() {
39 HttpSession session = sessionEvent.getSession(); 79 HttpSession session = sessionEvent.getSession();
40 - return session!=null ? session.getId() : null; 80 + return session != null ? session.getId() : null;
41 } 81 }
42 }); 82 });
43 } 83 }
impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml
@@ -47,6 +47,10 @@ @@ -47,6 +47,10 @@
47 <listener> 47 <listener>
48 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class> 48 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class>
49 </listener> 49 </listener>
  50 +
  51 + <listener>
  52 + <listener-class>br.gov.frameworkdemoiselle.util.RequestListener</listener-class>
  53 + </listener>
50 54
51 <filter> 55 <filter>
52 <filter-name>Demoiselle Servlet Filter</filter-name> 56 <filter-name>Demoiselle Servlet Filter</filter-name>