From 02b5874da1b080651ecfb6999845812934499d2f Mon Sep 17 00:00:00 2001 From: Danilo Costa Viana Date: Thu, 13 Aug 2015 12:06:32 -0300 Subject: [PATCH] [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 | 6 ++++++ archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml | 3 +++ impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java | 22 +++++++++------------- impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------ impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties | 3 ++- impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java | 40 +++++++++++++++++++++++++++++++++++++--- impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java | 40 +++++++++++++++++++++++++++++++++++++--- impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml | 4 ++++ 13 files changed, 558 insertions(+), 110 deletions(-) create mode 100644 impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java create mode 100644 impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java create mode 100644 impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java diff --git a/archetype/html-rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml b/archetype/html-rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml index 362c66f..72df141 100644 --- a/archetype/html-rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml +++ b/archetype/html-rest/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml @@ -15,6 +15,12 @@ br.gov.frameworkdemoiselle.util.ServletListener + + br.gov.frameworkdemoiselle.util.SessionListener + + + br.gov.frameworkdemoiselle.util.RequestListener + Demoiselle Servlet Filter br.gov.frameworkdemoiselle.util.ServletFilter diff --git a/archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml b/archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml index c617609..72cd1e6 100755 --- a/archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml +++ b/archetype/jsf-jpa/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml @@ -21,6 +21,9 @@ br.gov.frameworkdemoiselle.util.SessionListener + + br.gov.frameworkdemoiselle.util.RequestListener + Demoiselle Servlet Filter br.gov.frameworkdemoiselle.util.ServletFilter diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java index a89bbac..bede515 100644 --- a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/bootstrap/JsfBootstrap.java @@ -48,14 +48,11 @@ import br.gov.frameworkdemoiselle.util.Beans; public class JsfBootstrap implements Extension { - //private List customContexts = new ArrayList(); - - //private AfterBeanDiscovery afterBeanDiscoveryEvent; - private FacesViewContextImpl context; + private boolean contextActivatedHere; - - public void createCustomContext(@Observes AfterBeanDiscovery event){ + + public void createCustomContext(@Observes AfterBeanDiscovery event) { context = new FacesViewContextImpl(); event.addContext(context); } @@ -63,19 +60,18 @@ public class JsfBootstrap implements Extension { public void addContexts(@Observes final AfterDeploymentValidation event) { CustomContextProducer producer = Beans.getReference(CustomContextProducer.class); producer.addRegisteredContext(context); - - //Ativa o ViewContext - if (!context.isActive()){ + + // Ativa o ViewContext + if (!context.isActive()) { contextActivatedHere = context.activate(); - } - else{ + } else { contextActivatedHere = false; } } public void removeContexts(@Observes AfterShutdownProccess event) { - //Desativa o ViewContext - if (contextActivatedHere){ + // Desativa o ViewContext + if (contextActivatedHere) { context.deactivate(); } } diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java index 9adda0e..adde14b 100644 --- a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewBeanStore.java @@ -1,51 +1,120 @@ package br.gov.frameworkdemoiselle.internal.context; import java.io.Serializable; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import javax.enterprise.context.spi.Contextual; import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.Alternative; + +import br.gov.frameworkdemoiselle.context.ViewContext; +import br.gov.frameworkdemoiselle.util.ResourceBundle; /** - * Store that keeps view scoped beans. It associates all view scoped beans with a view ID. - * When the ID changes (meaning the view changed) all old view scoped beans are destroyed - * before new beans for the new view are created and stored. + * Store that keeps view scoped beans. It associates all view scoped beans with a view ID. When the ID changes (meaning + * the view changed) all old view scoped beans are destroyed before new beans for the new view are created and stored. * * @author SERPRO - * */ -@Alternative public class FacesViewBeanStore implements Serializable { private static final long serialVersionUID = -8265458933971929432L; - private Long lastViewId = null; + private final ConcurrentHashMap viewStore = new ConcurrentHashMap(); + + private long maxInactiveTimeInSeconds; - private BeanStore store; + public FacesViewBeanStore(long maxInactiveTimeInSeconds) { + this.maxInactiveTimeInSeconds = maxInactiveTimeInSeconds; + } - synchronized BeanStore getStore(Long viewId, AbstractCustomContext context) { - if (lastViewId == null || !lastViewId.equals(viewId)) { - clear(context); - lastViewId = viewId; - store = AbstractCustomContext.createStore(); + /** + * Gets the store that contains the view scoped beans for that view ID. If no store exists (new view) one is + * created. + * + * @param viewId + * ID of the current view + * @param context + * Reference to the {@link ViewContext} class managing the view scope + * @return The {@link BeanStore} that stores view scoped beans for this view ID + * @throws IllegalStateException + * if the view associated with the requested view ID has expired + */ + public BeanStore getStoreForView(Long viewId, AbstractCustomContext context) { + FacesViewData data = null; + synchronized (viewStore) { + data = viewStore.get(viewId); + if (data == null) { + BeanStore store = AbstractCustomContext.createStore(); + data = new FacesViewData(); + data.store = store; + viewStore.put(viewId, data); + } else if (data.isExpired(maxInactiveTimeInSeconds)) { + throw new IllegalStateException(ResourceBundle.getBundle("demoiselle-jsf-bundle").getString( + "view-expired")); + } } - return store; + data.lastTimeAccessed = System.currentTimeMillis(); + return data.store; } + /** + * @see #destroyStoresInSession(AbstractCustomContext, boolean) + */ + public void destroyStoresInSession(AbstractCustomContext context) { + destroyStoresInSession(context, false); + } + + /** + * Destroys all View scoped beans and the associated {@link BeanStore} for this user's session. The destroyed beans + * will respect CDI bean lifecycle, thus they'll trigger any events associated with destroying beans. + * + * @param context + * ViewContext managing the view scoped beans + * @param onlyExpired + * Only destroy beans if the underlying view has expired + */ @SuppressWarnings({ "rawtypes", "unchecked" }) - public void clear(AbstractCustomContext context) { - if (store != null) { - for (String id : store) { - Contextual contextual = context.getContextualStore().getContextual(id); - Object instance = store.getInstance(id); - CreationalContext creationalContext = store.getCreationalContext(id); - - if (contextual != null && instance != null) { - contextual.destroy(instance, creationalContext); + public void destroyStoresInSession(final AbstractCustomContext context, final boolean onlyExpired) { + for (Iterator> it = viewStore.entrySet().iterator(); it.hasNext();) { + Entry currentEntry = it.next(); + FacesViewData data = currentEntry.getValue(); + + if (data != null && data.store != null) { + if (!onlyExpired || data.isExpired(maxInactiveTimeInSeconds)) { + for (String id : data.store) { + Contextual contextual = context.getContextualStore().getContextual(id); + Object instance = data.store.getInstance(id); + CreationalContext creationalContext = data.store.getCreationalContext(id); + + if (contextual != null && instance != null) { + contextual.destroy(instance, creationalContext); + } + } + + data.store.clear(); + it.remove(); } } - store.clear(); + } + } + + /** + * Contains a {@link BeanStore} with some metadata, like the last time this store was accessed (used to determine + * when a store expires). + * + * @author serpro + */ + private static class FacesViewData { + + long lastTimeAccessed; + + BeanStore store; + + public synchronized boolean isExpired(long viewTimeoutInSeconds) { + return ((System.currentTimeMillis() - lastTimeAccessed) / 1000) > viewTimeoutInSeconds; } } } diff --git a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java index 6a54842..4018e38 100644 --- a/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java +++ b/impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/context/FacesViewContextImpl.java @@ -46,133 +46,193 @@ import javax.enterprise.event.Observes; import javax.enterprise.inject.Alternative; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import br.gov.frameworkdemoiselle.annotation.Priority; import br.gov.frameworkdemoiselle.context.ViewContext; +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestDestroyed; import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed; import br.gov.frameworkdemoiselle.lifecycle.ViewScoped; import br.gov.frameworkdemoiselle.util.Beans; import br.gov.frameworkdemoiselle.util.Faces; /** - * - * This {@link ViewContext} implementation uses a map provided - * by {@link UIViewRoot#getViewMap()} as a store. Any beans stored on - * this store are kept as long as the view is still active. + * This {@link ViewContext} implementation uses a map provided by {@link UIViewRoot#getViewMap()} as a store. Any beans + * stored on this store are kept as long as the view is still active. * * @author serpro - * */ @Priority(Priority.L2_PRIORITY) @Alternative public class FacesViewContextImpl extends AbstractCustomContext implements ViewContext { - + private final AtomicLong atomicLong = new AtomicLong(); - - private ConcurrentHashMap sessionBeanStore = new ConcurrentHashMap(); - + + // Armazena todas as views relacionadas à sessão atual. Quando uma sessão + // termina, o store correspondente é destruído. + private ConcurrentHashMap viewStoreInSession = new ConcurrentHashMap(); + private static final String FACES_KEY = FacesViewContextImpl.class.getCanonicalName(); - + public FacesViewContextImpl() { super(ViewScoped.class); } - + @Override protected boolean isStoreInitialized() { - return FacesContext.getCurrentInstance()!=null && getSessionId()!=null; + return FacesContext.getCurrentInstance() != null && getSessionId() != null; } @Override protected BeanStore getStore() { String sessionId = getSessionId(); - if (sessionId == null){ + if (sessionId == null) { return null; } - + /* - * Tenta obter o viewID de forma não thread-safe por questões de performance. - * Se o viewID não existe entra em um trecho thread-safe para incrementa-lo, evitando - * conflito entre duas requests tentando incrementar esse número. + * Tenta obter o viewID de forma não thread-safe por questões de performance. Se o viewID não existe entra em um + * trecho thread-safe para incrementa-lo, evitando conflito entre duas requests tentando incrementar esse + * número. */ - Long viewId = (Long)Faces.getViewMap().get(FACES_KEY); - if (viewId==null){ + Long viewId = (Long) Faces.getViewMap().get(FACES_KEY); + if (viewId == null) { synchronized (this) { - - //Tenta obte-lo novamente, caso entre a primeira tentativa e o bloqueio - //da thread outra thread já tenha criado o número. - viewId = (Long)Faces.getViewMap().get(FACES_KEY); - if (viewId==null){ + + // Tenta obte-lo novamente, caso entre a primeira tentativa e o + // bloqueio + // da thread outra thread já tenha criado o número. + viewId = (Long) Faces.getViewMap().get(FACES_KEY); + if (viewId == null) { viewId = atomicLong.incrementAndGet(); Faces.getViewMap().put(FACES_KEY, viewId); } } } - //A mesma técnica de bloqueio de thread acima é usada aqui para - //criar um SessionBeanStore caso o mesmo ainda não exista. - FacesViewBeanStore currentStore = sessionBeanStore.get(sessionId); - if (currentStore==null){ + // A mesma técnica de bloqueio de thread acima é usada aqui para + // criar um FacesViewBeanStore caso o mesmo ainda não exista, e + // associa-lo à sessão atual. + FacesViewBeanStore currentViewStore = viewStoreInSession.get(sessionId); + if (currentViewStore == null) { synchronized (this) { - currentStore = (FacesViewBeanStore) sessionBeanStore.get(sessionId); - if (currentStore==null){ - currentStore = new FacesViewBeanStore(); - sessionBeanStore.put(sessionId, currentStore); + currentViewStore = (FacesViewBeanStore) viewStoreInSession.get(sessionId); + if (currentViewStore == null) { + currentViewStore = new FacesViewBeanStore(getSessionTimeout()); + viewStoreInSession.put(sessionId, currentViewStore); } } } - return currentStore.getStore(viewId, this); + return currentViewStore.getStoreForView(viewId, this); } - + /* * Called before the session is invalidated for that user. * Destroys all view scoped beans stored on that session. */ - private void clearInvalidatedSession(String sessionId){ - if (sessionId != null){ - final FacesViewBeanStore store = sessionBeanStore.get(sessionId); - if (store!=null){ - store.clear(this); - sessionBeanStore.remove(sessionId); + private void clearInvalidatedSession(String sessionId) { + if (sessionId != null) { + final FacesViewBeanStore store = viewStoreInSession.get(sessionId); + if (store != null) { + store.destroyStoresInSession(this); + viewStoreInSession.remove(sessionId); + } + } + } + + /* + * Called at each new request at a given session. + * Destroys any expired views. + */ + private synchronized void clearExpiredViews(String sessionId) { + if (sessionId != null) { + final FacesViewBeanStore store = viewStoreInSession.get(sessionId); + if (store != null) { + store.destroyStoresInSession(this, true); } } } - + + /* + * Returns the current session ID. Creates a session if one doesn't exist. + * Returns NULL if the session can't be created. + */ + private String getSessionId() { + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext() + .getSession(true); + return session != null ? session.getId() : null; + } + /* - * Returns the current session ID. Creates a session if one doesn't exist. Returns NULL if the session can't be created. + * Returns the configured session timeout in seconds. This is the maximum + * inactive interval, not the remaining timeout for this session. */ - private String getSessionId(){ - final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true); - return session!=null ? session.getId() : null; + private int getSessionTimeout() { + final HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext() + .getSession(true); + return session != null ? session.getMaxInactiveInterval() : 0; } - + /** - * Observes HTTP session lifecycle and notifies the ViewContext of session events (creation or destruction) - * so view scoped beans can be created or destroyed based on their underlying session scopes. + * Observes HTTP servlet lifecycle and notifies the ViewContext of session events (creation or destruction) + * and request events (before going into scope and before going out of scope) so view + * scoped beans can be created or destroyed based on their underlying session and request scopes. * * @author SERPRO - * */ @ApplicationScoped - protected static class FacesViewSessionListener { - + protected static class ServletEventListener { + /** - * Called before the session is invalidated for that user. - * Destroys all view scoped beans stored on that session. + * Called before the session is invalidated for that user. Destroys all view scoped beans stored on that + * session. */ - protected void clearInvalidatedSession(@Observes BeforeSessionDestroyed event){ + protected void clearInvalidatedSession(@Observes BeforeSessionDestroyed event) { String sessionId = event.getSessionId(); - try{ + try { Context context = Beans.getBeanManager().getContext(ViewScoped.class); - if ( FacesViewContextImpl.class.isInstance(context) ){ - ((FacesViewContextImpl)context).clearInvalidatedSession(sessionId); + if (FacesViewContextImpl.class.isInstance(context)) { + ((FacesViewContextImpl) context).clearInvalidatedSession(sessionId); } + } catch (ContextNotActiveException ce) { + // Nada a fazer, contexto não está ativo. } - catch(ContextNotActiveException ce){ - //Nada a fazer, contexto não está ativo. + } + + /** + * Called before the current request is about to go out of scope. Checks if any currently + * active views have expired and requests the destruction of those beans according to CDI + * lifecycle. + * + */ + protected void clearExpiredViews(@Observes BeforeRequestDestroyed event) { + ServletRequest request = event.getRequest(); + + if (HttpServletRequest.class.isInstance(request)) { + HttpSession session = ((HttpServletRequest) request).getSession(false); + + if (session != null) { + try { + final Context context = Beans.getBeanManager().getContext(ViewScoped.class); + final String currentSessionId = session.getId(); + + if (FacesViewContextImpl.class.isInstance(context)) { + new Thread() { + + @Override + public void run() { + ((FacesViewContextImpl) context).clearExpiredViews(currentSessionId); + } + }.start(); + } + } catch (ContextNotActiveException ce) { + // Nada a fazer, contexto não está ativo. + } + } } } } } - diff --git a/impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties b/impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties index 5fccbda..3a9a5a4 100644 --- a/impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties +++ b/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 " 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" 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" 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" -faces-context-not-available=N\u00E3o existe uma inst\u00E2ncia de FacesContext ativa para esse escopo \ No newline at end of file +faces-context-not-available=N\u00E3o existe uma inst\u00E2ncia de FacesContext ativa para esse escopo +view-expired=A vis\u00E3o referenciada por essa tela expirou. \ No newline at end of file diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java index 1a2421c..84ab1be 100644 --- a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/AfterSessionCreated.java @@ -1,15 +1,49 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ package br.gov.frameworkdemoiselle.lifecycle; /** * This interface represents an event fired after a new HTTP session is created. * * @author serpro - * */ public interface AfterSessionCreated { - + /** - * * @return The ID of the recently created session */ public String getSessionId(); diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java new file mode 100644 index 0000000..76bb136 --- /dev/null +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestDestroyed.java @@ -0,0 +1,53 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.lifecycle; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; + +/** + * Event fired just before a request is about to go out of scope + * + * @author serpro + */ +public interface BeforeRequestDestroyed { + + public ServletRequest getRequest(); + + public ServletContext getServletContext(); + +} diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java new file mode 100644 index 0000000..c7d1a70 --- /dev/null +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeRequestInitialized.java @@ -0,0 +1,54 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.lifecycle; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; + +/** + * Event fired just before a request is about to come into scope. + * + * @author serpro + * + */ +public interface BeforeRequestInitialized { + + public ServletRequest getRequest(); + + public ServletContext getServletContext(); + +} diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java index 0453179..3bf266b 100644 --- a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/lifecycle/BeforeSessionDestroyed.java @@ -1,15 +1,49 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ package br.gov.frameworkdemoiselle.lifecycle; /** * This interface represents an event fired before an HTTP session is destroyed. * * @author serpro - * */ public interface BeforeSessionDestroyed { - + /** - * * @return The session ID of the session about to be destroyed */ public String getSessionId(); diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java new file mode 100644 index 0000000..e626fc3 --- /dev/null +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/RequestListener.java @@ -0,0 +1,94 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.util; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; + +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestDestroyed; +import br.gov.frameworkdemoiselle.lifecycle.BeforeRequestInitialized; + +/** + *

+ * Implements the {@link javax.servlet.ServletRequestListener} interface and fires two events. + *

+ *
    + *
  • {@link BeforeRequestInitialized}: Just before a new HTTP request comes into scope
  • + *
  • {@link BeforeRequestDestroyed}: Just before an HTTP request will go out of scope
  • + *
+ * + * @author serpro + */ +@WebListener +public class RequestListener implements ServletRequestListener { + + @Override + public void requestDestroyed(final ServletRequestEvent sre) { + Beans.getBeanManager().fireEvent(new BeforeRequestDestroyed() { + + @Override + public ServletRequest getRequest() { + return sre.getServletRequest(); + } + + @Override + public ServletContext getServletContext() { + return sre.getServletContext(); + } + }); + } + + @Override + public void requestInitialized(final ServletRequestEvent sre) { + Beans.getBeanManager().fireEvent(new BeforeRequestDestroyed() { + + @Override + public ServletRequest getRequest() { + return sre.getServletRequest(); + } + + @Override + public ServletContext getServletContext() { + return sre.getServletContext(); + } + }); + } + +} diff --git a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java index 508a5dc..5376392 100644 --- a/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java +++ b/impl/extension/servlet/src/main/java/br/gov/frameworkdemoiselle/util/SessionListener.java @@ -1,5 +1,42 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ package br.gov.frameworkdemoiselle.util; +import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; @@ -8,25 +45,27 @@ import br.gov.frameworkdemoiselle.lifecycle.AfterSessionCreated; import br.gov.frameworkdemoiselle.lifecycle.BeforeSessionDestroyed; /** - *

Implements the {@link HttpSessionListener} interface and fires two events.

- * + *

+ * Implements the {@link HttpSessionListener} interface and fires two events. + *

*
    *
  • {@link AfterSessionCreated}: Just after a new HTTP session is created
  • *
  • {@link BeforeSessionDestroyed}: Just before an HTTP session is invalidated
  • *
* * @author serpro - * */ +@WebListener public class SessionListener implements HttpSessionListener { - + @Override public void sessionCreated(final HttpSessionEvent sessionEvent) { Beans.getBeanManager().fireEvent(new AfterSessionCreated() { + @Override public String getSessionId() { HttpSession session = sessionEvent.getSession(); - return session!=null ? session.getId() : null; + return session != null ? session.getId() : null; } }); } @@ -34,10 +73,11 @@ public class SessionListener implements HttpSessionListener { @Override public void sessionDestroyed(final HttpSessionEvent sessionEvent) { Beans.getBeanManager().fireEvent(new BeforeSessionDestroyed() { + @Override public String getSessionId() { HttpSession session = sessionEvent.getSession(); - return session!=null ? session.getId() : null; + return session != null ? session.getId() : null; } }); } diff --git a/impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml b/impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml index 7a0b5f1..8aac94d 100644 --- a/impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml +++ b/impl/extension/servlet/src/main/resources/META-INF/web-fragment.xml @@ -47,6 +47,10 @@ br.gov.frameworkdemoiselle.util.SessionListener + + + br.gov.frameworkdemoiselle.util.RequestListener + Demoiselle Servlet Filter -- libgit2 0.21.2