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 15 <listener>
16 16 <listener-class>br.gov.frameworkdemoiselle.util.ServletListener</listener-class>
17 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 24 <filter>
19 25 <filter-name>Demoiselle Servlet Filter</filter-name>
20 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 21 <listener>
22 22 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class>
23 23 </listener>
  24 + <listener>
  25 + <listener-class>br.gov.frameworkdemoiselle.util.RequestListener</listener-class>
  26 + </listener>
24 27 <filter>
25 28 <filter-name>Demoiselle Servlet Filter</filter-name>
26 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 48  
49 49 public class JsfBootstrap implements Extension {
50 50  
51   - //private List<CustomContext> customContexts = new ArrayList<CustomContext>();
52   -
53   - //private AfterBeanDiscovery afterBeanDiscoveryEvent;
54   -
55 51 private FacesViewContextImpl context;
  52 +
56 53 private boolean contextActivatedHere;
57   -
58   - public void createCustomContext(@Observes AfterBeanDiscovery event){
  54 +
  55 + public void createCustomContext(@Observes AfterBeanDiscovery event) {
59 56 context = new FacesViewContextImpl();
60 57 event.addContext(context);
61 58 }
... ... @@ -63,19 +60,18 @@ public class JsfBootstrap implements Extension {
63 60 public void addContexts(@Observes final AfterDeploymentValidation event) {
64 61 CustomContextProducer producer = Beans.getReference(CustomContextProducer.class);
65 62 producer.addRegisteredContext(context);
66   -
67   - //Ativa o ViewContext
68   - if (!context.isActive()){
  63 +
  64 + // Ativa o ViewContext
  65 + if (!context.isActive()) {
69 66 contextActivatedHere = context.activate();
70   - }
71   - else{
  67 + } else {
72 68 contextActivatedHere = false;
73 69 }
74 70 }
75 71  
76 72 public void removeContexts(@Observes AfterShutdownProccess event) {
77   - //Desativa o ViewContext
78   - if (contextActivatedHere){
  73 + // Desativa o ViewContext
  74 + if (contextActivatedHere) {
79 75 context.deactivate();
80 76 }
81 77 }
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java
1 1 package br.gov.frameworkdemoiselle.internal.context;
2 2  
3 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 8 import javax.enterprise.context.spi.Contextual;
6 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 18 * @author SERPRO
15   - *
16 19 */
17   -@Alternative
18 20 public class FacesViewBeanStore implements Serializable {
19 21  
20 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 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 46 import javax.enterprise.inject.Alternative;
47 47 import javax.faces.component.UIViewRoot;
48 48 import javax.faces.context.FacesContext;
  49 +import javax.servlet.ServletRequest;
  50 +import javax.servlet.http.HttpServletRequest;
49 51 import javax.servlet.http.HttpSession;
50 52  
51 53 import br.gov.frameworkdemoiselle.annotation.Priority;
52 54 import br.gov.frameworkdemoiselle.context.ViewContext;
  55 +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestDestroyed;
53 56 import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed;
54 57 import br.gov.frameworkdemoiselle.lifecycle.ViewScoped;
55 58 import br.gov.frameworkdemoiselle.util.Beans;
56 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 65 * @author serpro
65   - *
66 66 */
67 67 @Priority(Priority.L2_PRIORITY)
68 68 @Alternative
69 69 public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext {
70   -
  70 +
71 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 77 private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName();
76   -
  78 +
77 79 public FacesViewContextImpl() {
78 80 super(ViewScoped.class);
79 81 }
80   -
  82 +
81 83 @Override
82 84 protected boolean isStoreInitialized() {
83   - return FacesContext.getCurrentInstance()!=null && getSessionId()!=null;
  85 + return FacesContext.getCurrentInstance() != null && getSessionId() != null;
84 86 }
85 87  
86 88 @Override
87 89 protected BeanStore getStore() {
88 90 String sessionId = getSessionId();
89   - if (sessionId == null){
  91 + if (sessionId == null) {
90 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 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 109 viewId = atomicLong.incrementAndGet();
107 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 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 133 * Called before the session is invalidated for that user.
130 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 184 * @author SERPRO
155   - *
156 185 */
157 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 194 String sessionId = event.getSessionId();
166   - try{
  195 + try {
167 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 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 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 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 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 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 37 package br.gov.frameworkdemoiselle.lifecycle;
2 38  
3 39 /**
4 40 * This interface represents an event fired after a new HTTP session is created.
5 41 *
6 42 * @author serpro
7   - *
8 43 */
9 44 public interface AfterSessionCreated {
10   -
  45 +
11 46 /**
12   - *
13 47 * @return The ID of the recently created session
14 48 */
15 49 public String getSessionId();
... ...
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java 0 → 100644
... ... @@ -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 @@
  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 37 package br.gov.frameworkdemoiselle.lifecycle;
2 38  
3 39 /**
4 40 * This interface represents an event fired before an HTTP session is destroyed.
5 41 *
6 42 * @author serpro
7   - *
8 43 */
9 44 public interface BeforeSessionDestroyed {
10   -
  45 +
11 46 /**
12   - *
13 47 * @return The session ID of the session about to be destroyed
14 48 */
15 49 public String getSessionId();
... ...
impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java 0 → 100644
... ... @@ -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 37 package br.gov.frameworkdemoiselle.util;
2 38  
  39 +import javax.servlet.annotation.WebListener;
3 40 import javax.servlet.http.HttpSession;
4 41 import javax.servlet.http.HttpSessionEvent;
5 42 import javax.servlet.http.HttpSessionListener;
... ... @@ -8,25 +45,27 @@ import br.gov.frameworkdemoiselle.lifecycle.AfterSessionCreated;
8 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 51 * <ul>
14 52 * <li><strong>{@link AfterSessionCreated}</strong>: Just after a new HTTP session is created</li>
15 53 * <li><strong>{@link BeforeSessionDestroyed}</strong>: Just before an HTTP session is invalidated</li>
16 54 * </ul>
17 55 *
18 56 * @author serpro
19   - *
20 57 */
  58 +@WebListener
21 59 public class SessionListener implements HttpSessionListener {
22   -
  60 +
23 61 @Override
24 62 public void sessionCreated(final HttpSessionEvent sessionEvent) {
25 63 Beans.getBeanManager().fireEvent(new AfterSessionCreated() {
  64 +
26 65 @Override
27 66 public String getSessionId() {
28 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 73 @Override
35 74 public void sessionDestroyed(final HttpSessionEvent sessionEvent) {
36 75 Beans.getBeanManager().fireEvent(new BeforeSessionDestroyed() {
  76 +
37 77 @Override
38 78 public String getSessionId() {
39 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 47 <listener>
48 48 <listener-class>br.gov.frameworkdemoiselle.util.SessionListener</listener-class>
49 49 </listener>
  50 +
  51 + <listener>
  52 + <listener-class>br.gov.frameworkdemoiselle.util.RequestListener</listener-class>
  53 + </listener>
50 54  
51 55 <filter>
52 56 <filter-name>Demoiselle Servlet Filter</filter-name>
... ...