Commit f7a18fbf416e9b010f685c7bf0a22f43cc482460

Authored by Danilo Costa Viana
1 parent 97dc65cc
Exists in master

[FWK-234] Removido FacesContextProxy, introduzido FacesContextProducer e

foram tomadas medidas para disparar erros caso o desenvolvedor tente
injetar referências de FacesContext em atributos de classes
serializáveis (nesse caso o atributo deve ser transient).
impl/core/src/main/java/br/gov/frameworkdemoiselle/util/Beans.java
... ... @@ -77,6 +77,30 @@ public final class Beans {
77 77 return beanManager;
78 78 }
79 79  
  80 + /**
  81 + * Obtains a injectble instance of a bean, which have the given EL name and are available for injection in the point
  82 + * where this method was call.
  83 + *
  84 + * @param beanName
  85 + * the EL name for the requested bean.
  86 + * @return Type a instace of the injected beanClass.
  87 + * @throws DemoiselleException
  88 + * if no bean are avaliable to be injected for the given bean name.
  89 + */
  90 + public static <T> T getReference(String beanName) {
  91 + T instance;
  92 +
  93 + try {
  94 + instance = (T) createReference(getBeanManager().getBeans(beanName), (Class<T>) null);
  95 +
  96 + } catch (NoSuchElementException cause) {
  97 + String message = getBundle().getString("bean-not-found", beanName);
  98 + throw new DemoiselleException(message, cause);
  99 + }
  100 +
  101 + return instance;
  102 + }
  103 +
80 104 public static <T> T getReference(final Class<T> beanClass) {
81 105 return getReference(beanClass, (Annotation[]) null);
82 106 }
... ... @@ -104,7 +128,7 @@ public final class Beans {
104 128 beans = getBeanManager().getBeans(beanClass, qualifiers);
105 129 }
106 130  
107   - instance = (T) getReference(beans, beanClass, qualifiers);
  131 + instance = (T) createReference(beans, beanClass, qualifiers);
108 132  
109 133 } catch (NoSuchElementException cause) {
110 134 StringBuffer buffer = new StringBuffer();
... ... @@ -124,33 +148,8 @@ public final class Beans {
124 148 return instance;
125 149 }
126 150  
127   - /**
128   - * Obtains a injectble instance of a bean, which have the given EL name and are available for injection in the point
129   - * where this method was call.
130   - *
131   - * @param beanName
132   - * the EL name for the requested bean.
133   - * @return Type a instace of the injected beanClass.
134   - * @throws DemoiselleException
135   - * if no bean are avaliable to be injected for the given bean name.
136   - */
137   - @SuppressWarnings("unchecked")
138   - public static <T> T getReference(String beanName) {
139   - T instance;
140   -
141   - try {
142   - instance = (T) getReference(getBeanManager().getBeans(beanName));
143   -
144   - } catch (NoSuchElementException cause) {
145   - String message = getBundle().getString("bean-not-found", beanName);
146   - throw new DemoiselleException(message, cause);
147   - }
148   -
149   - return instance;
150   - }
151   -
152 151 @SuppressWarnings("unchecked")
153   - private static <T> T getReference(Set<Bean<?>> beans, Class<T> beanClass, Annotation... qualifiers) {
  152 + private static <T> T createReference(Set<Bean<?>> beans, Class<T> beanClass, Annotation... qualifiers) {
154 153 if (beans.size() > 1) {
155 154 String message = getBundle().getString("ambiguous-bean-resolution", beanClass.getName(), beans.toString());
156 155 throw new DemoiselleException(message, new AmbiguousResolutionException());
... ... @@ -162,23 +161,42 @@ public final class Beans {
162 161 InjectionPoint injectionPoint;
163 162  
164 163 if (qualifiers == null) {
165   - injectionPoint = new CustomInjectionPoint(bean, beanType);
  164 + injectionPoint = new ProgramaticInjectionPoint(bean, beanType);
166 165 } else {
167   - injectionPoint = new CustomInjectionPoint(bean, beanType, qualifiers);
  166 + injectionPoint = new ProgramaticInjectionPoint(bean, beanType, qualifiers);
168 167 }
169 168  
170 169 return (T) getBeanManager().getInjectableReference(injectionPoint, context);
171 170 }
172 171  
173   - private static <T> T getReference(Set<Bean<?>> beans) {
174   - return getReference(beans, (Class<T>) null);
175   - }
  172 + /*
  173 + * private static <T> T getReference(Set<Bean<?>> beans) { return getReference(beans, (Class<T>) null, (Member)
  174 + * null); }
  175 + */
176 176  
177 177 private static ResourceBundle getBundle() {
178 178 return Beans.getReference(ResourceBundle.class, new NameQualifier("demoiselle-core-bundle"));
179 179 }
180 180  
181   - static class CustomInjectionPoint implements InjectionPoint {
  181 + /**
  182 + * <p>
  183 + * A dummy injection point created when getting a new bean through one of the {@link Beans#getReference} methods.
  184 + * </p>
  185 + * <p>
  186 + * This dummy injection point returns valid values for {@link #getBean()}, {@link #getType()} and
  187 + * {@link #getQualifiers()} methods, but it always returns <code>null</code> for {@link #getMember()} as there is no
  188 + * real class member where the bean was injected.
  189 + * </p>
  190 + * <p>
  191 + * This injection point also always return <code>false</code> for {@link #isDelegate()} and {@link #isTransient()}.
  192 + * In the case of {@link #isTransient()} there is no real way to know if the field receiving the value of
  193 + * {@link Beans#getReference} is transient, so take special care when assigning non-serializable beans into
  194 + * non-transient fields of serializable classes.
  195 + * </p>
  196 + *
  197 + * @author SERPRO
  198 + */
  199 + public static final class ProgramaticInjectionPoint implements InjectionPoint {
182 200  
183 201 private final Bean<?> bean;
184 202  
... ... @@ -186,7 +204,7 @@ public final class Beans {
186 204  
187 205 private final Set<Annotation> qualifiers;
188 206  
189   - public CustomInjectionPoint(Bean<?> bean, Type beanType, Annotation... qualifiers) {
  207 + public ProgramaticInjectionPoint(Bean<?> bean, Type beanType, Annotation... qualifiers) {
190 208 this.bean = bean;
191 209 this.beanType = beanType;
192 210 this.qualifiers = new HashSet<Annotation>(Arrays.asList(qualifiers));
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/procuder/FacesContextProducer.java 0 → 100644
... ... @@ -0,0 +1,93 @@
  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 +/*
  38 + * Demoiselle Framework Copyright (c) 2010 Serpro and other contributors as indicated by the @author tag. See the
  39 + * copyright.txt in the distribution for a full listing of contributors. Demoiselle Framework is an open source Java EE
  40 + * library designed to accelerate the development of transactional database Web applications. Demoiselle Framework is
  41 + * released under the terms of the LGPL license 3 http://www.gnu.org/licenses/lgpl.html LGPL License 3 This file is part
  42 + * of Demoiselle Framework. Demoiselle Framework is free software: you can redistribute it and/or modify it under the
  43 + * terms of the GNU Lesser General Public License 3 as published by the Free Software Foundation. Demoiselle Framework
  44 + * is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  45 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You
  46 + * should have received a copy of the GNU Lesser General Public License along with Demoiselle Framework. If not, see
  47 + * <http://www.gnu.org/licenses/>.
  48 + */
  49 +package br.gov.frameworkdemoiselle.internal.procuder;
  50 +
  51 +import java.io.NotSerializableException;
  52 +import java.io.Serializable;
  53 +import java.lang.reflect.Member;
  54 +import java.util.logging.Logger;
  55 +
  56 +import javax.enterprise.context.ContextNotActiveException;
  57 +import javax.enterprise.context.Dependent;
  58 +import javax.enterprise.inject.Produces;
  59 +import javax.enterprise.inject.spi.InjectionPoint;
  60 +import javax.faces.context.FacesContext;
  61 +
  62 +import br.gov.frameworkdemoiselle.DemoiselleException;
  63 +import br.gov.frameworkdemoiselle.annotation.Name;
  64 +import br.gov.frameworkdemoiselle.util.Beans.ProgramaticInjectionPoint;
  65 +import br.gov.frameworkdemoiselle.util.ResourceBundle;
  66 +
  67 +public class FacesContextProducer {
  68 +
  69 + @Produces
  70 + @Dependent
  71 + public FacesContext create(InjectionPoint ip, @Name("demoiselle-jsf-bundle") ResourceBundle bundle, Logger logger) {
  72 + if (ip != null && !ip.isTransient()) {
  73 + final Member member = ip.getMember();
  74 + if (member != null) {
  75 + Class<?> declaringClass = member.getDeclaringClass();
  76 + if (Serializable.class.isAssignableFrom(declaringClass)) {
  77 + throw new DemoiselleException(bundle.getString("faces-context-not-passivable", member.getName(),
  78 + declaringClass.getCanonicalName()), new NotSerializableException(
  79 + FacesContext.class.getCanonicalName()));
  80 + }
  81 + } else if (ProgramaticInjectionPoint.class.isInstance(ip)) {
  82 + logger.fine(bundle.getString("faces-context-passivation-warning"));
  83 + }
  84 + }
  85 +
  86 + FacesContext context = FacesContext.getCurrentInstance();
  87 + if (context == null) {
  88 + throw new ContextNotActiveException(bundle.getString("faces-context-not-available"));
  89 + }
  90 +
  91 + return context;
  92 + }
  93 +}
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/internal/proxy/FacesContextProxy.java
... ... @@ -1,205 +0,0 @@
1   -package br.gov.frameworkdemoiselle.internal.proxy;
2   -
3   -import java.io.Serializable;
4   -import java.util.Iterator;
5   -import java.util.List;
6   -import java.util.Map;
7   -
8   -import javax.annotation.PostConstruct;
9   -import javax.el.ELContext;
10   -import javax.enterprise.context.ContextNotActiveException;
11   -import javax.enterprise.inject.Default;
12   -import javax.faces.application.Application;
13   -import javax.faces.application.FacesMessage;
14   -import javax.faces.application.FacesMessage.Severity;
15   -import javax.faces.application.ProjectStage;
16   -import javax.faces.component.UIViewRoot;
17   -import javax.faces.context.ExceptionHandler;
18   -import javax.faces.context.ExternalContext;
19   -import javax.faces.context.FacesContext;
20   -import javax.faces.context.PartialViewContext;
21   -import javax.faces.context.ResponseStream;
22   -import javax.faces.context.ResponseWriter;
23   -import javax.faces.event.PhaseId;
24   -import javax.faces.render.RenderKit;
25   -import javax.inject.Inject;
26   -
27   -import br.gov.frameworkdemoiselle.annotation.Name;
28   -import br.gov.frameworkdemoiselle.util.ResourceBundle;
29   -
30   -@Default
31   -public class FacesContextProxy extends FacesContext implements Serializable {
32   -
33   - private static final long serialVersionUID = 1L;
34   -
35   - @Inject
36   - @Name("demoiselle-jsf-bundle")
37   - private ResourceBundle bundle;
38   -
39   - @PostConstruct
40   - protected void initialize() {
41   - getDelegate();
42   - }
43   -
44   - public FacesContext getDelegate() {
45   - FacesContext facesContext = FacesContext.getCurrentInstance();
46   -
47   - if (facesContext == null) {
48   - throw new ContextNotActiveException(bundle.getString("faces-context-not-available"));
49   - }
50   -
51   - return facesContext;
52   - }
53   -
54   - public int hashCode() {
55   - return getDelegate().hashCode();
56   - }
57   -
58   - public boolean equals(Object obj) {
59   - return getDelegate().equals(obj);
60   - }
61   -
62   - public Application getApplication() {
63   - return getDelegate().getApplication();
64   - }
65   -
66   - public Map<Object, Object> getAttributes() {
67   - return getDelegate().getAttributes();
68   - }
69   -
70   - public PartialViewContext getPartialViewContext() {
71   - return getDelegate().getPartialViewContext();
72   - }
73   -
74   - public Iterator<String> getClientIdsWithMessages() {
75   - return getDelegate().getClientIdsWithMessages();
76   - }
77   -
78   - public String toString() {
79   - return getDelegate().toString();
80   - }
81   -
82   - public ELContext getELContext() {
83   - return getDelegate().getELContext();
84   - }
85   -
86   - public ExceptionHandler getExceptionHandler() {
87   - return getDelegate().getExceptionHandler();
88   - }
89   -
90   - public void setExceptionHandler(ExceptionHandler exceptionHandler) {
91   - getDelegate().setExceptionHandler(exceptionHandler);
92   - }
93   -
94   - public ExternalContext getExternalContext() {
95   - return getDelegate().getExternalContext();
96   - }
97   -
98   - public Severity getMaximumSeverity() {
99   - return getDelegate().getMaximumSeverity();
100   - }
101   -
102   - public Iterator<FacesMessage> getMessages() {
103   - return getDelegate().getMessages();
104   - }
105   -
106   - public List<FacesMessage> getMessageList() {
107   - return getDelegate().getMessageList();
108   - }
109   -
110   - public List<FacesMessage> getMessageList(String clientId) {
111   - return getDelegate().getMessageList(clientId);
112   - }
113   -
114   - public Iterator<FacesMessage> getMessages(String clientId) {
115   - return getDelegate().getMessages(clientId);
116   - }
117   -
118   - public RenderKit getRenderKit() {
119   - return getDelegate().getRenderKit();
120   - }
121   -
122   - public boolean getRenderResponse() {
123   - return getDelegate().getRenderResponse();
124   - }
125   -
126   - public boolean getResponseComplete() {
127   - return getDelegate().getResponseComplete();
128   - }
129   -
130   - public boolean isValidationFailed() {
131   - return getDelegate().isValidationFailed();
132   - }
133   -
134   - public ResponseStream getResponseStream() {
135   - return getDelegate().getResponseStream();
136   - }
137   -
138   - public void setResponseStream(ResponseStream responseStream) {
139   - getDelegate().setResponseStream(responseStream);
140   - }
141   -
142   - public ResponseWriter getResponseWriter() {
143   - return getDelegate().getResponseWriter();
144   - }
145   -
146   - public void setResponseWriter(ResponseWriter responseWriter) {
147   - getDelegate().setResponseWriter(responseWriter);
148   - }
149   -
150   - public UIViewRoot getViewRoot() {
151   - return getDelegate().getViewRoot();
152   - }
153   -
154   - public void setViewRoot(UIViewRoot root) {
155   - getDelegate().setViewRoot(root);
156   - }
157   -
158   - public void addMessage(String clientId, FacesMessage message) {
159   - getDelegate().addMessage(clientId, message);
160   - }
161   -
162   - public boolean isReleased() {
163   - return getDelegate().isReleased();
164   - }
165   -
166   - public void release() {
167   - getDelegate().release();
168   - }
169   -
170   - public void renderResponse() {
171   - getDelegate().renderResponse();
172   - }
173   -
174   - public boolean isPostback() {
175   - return getDelegate().isPostback();
176   - }
177   -
178   - public void responseComplete() {
179   - getDelegate().responseComplete();
180   - }
181   -
182   - public void validationFailed() {
183   - getDelegate().validationFailed();
184   - }
185   -
186   - public PhaseId getCurrentPhaseId() {
187   - return getDelegate().getCurrentPhaseId();
188   - }
189   -
190   - public void setCurrentPhaseId(PhaseId currentPhaseId) {
191   - getDelegate().setCurrentPhaseId(currentPhaseId);
192   - }
193   -
194   - public void setProcessingEvents(boolean processingEvents) {
195   - getDelegate().setProcessingEvents(processingEvents);
196   - }
197   -
198   - public boolean isProcessingEvents() {
199   - return getDelegate().isProcessingEvents();
200   - }
201   -
202   - public boolean isProjectStage(ProjectStage stage) {
203   - return getDelegate().isProjectStage(stage);
204   - }
205   -}
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/template/AbstractEditPageBean.java
... ... @@ -76,7 +76,7 @@ public abstract class AbstractEditPageBean&lt;T, I&gt; extends AbstractPageBean implem
76 76 private ResourceBundle bundle;
77 77  
78 78 @Inject
79   - private FacesContext facesContext;
  79 + private transient FacesContext facesContext;
80 80  
81 81 protected void clear() {
82 82 this.id = null;
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/template/AbstractPageBean.java
... ... @@ -53,7 +53,7 @@ public abstract class AbstractPageBean implements PageBean {
53 53 private static final long serialVersionUID = 1L;
54 54  
55 55 @Inject
56   - private FacesContext facesContext;
  56 + private transient FacesContext facesContext;
57 57  
58 58 private String nextView;
59 59  
... ...
impl/extension/jsf/src/main/java/br/gov/frameworkdemoiselle/util/Locales.java
... ... @@ -65,7 +65,7 @@ public class Locales implements Serializable {
65 65 }
66 66  
67 67 @Inject
68   - private FacesContext facesContext;
  68 + private transient FacesContext facesContext;
69 69  
70 70 /**
71 71 * Set the language to "en_US". This is a shorthand to <code>setLocale(Locale.US)</code>.
... ...
impl/extension/jsf/src/main/resources/demoiselle-jsf-bundle.properties
... ... @@ -34,8 +34,10 @@
34 34 # 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
35 35  
36 36 id-converter-not-found=Voc\u00EA precisa criar um FacesConverter para a classe "{0}".
  37 +faces-context-passivation-warning=FacesContext obtido atrav\u00E9s de Beans.getReference. Se valor for atribuido a um atributo de classe, certifique-se que a classe n\u00E3o implementa [Serializable] ou que o atributo \u00E9 marcado como [transient].
37 38 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 39 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 40 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 41 faces-context-not-available=N\u00E3o existe uma inst\u00E2ncia de FacesContext ativa para esse escopo
41   -view-expired=A vis\u00E3o referenciada por essa tela expirou.
42 42 \ No newline at end of file
  43 +view-expired=A vis\u00E3o referenciada por essa tela expirou.
  44 +faces-context-not-passivable=FacesContext n\u00E3o \u00E9 uma classe serializ\u00E1vel e n\u00E3o deve ser injetada em atributos de classes serializ\u00E1veis. Declare o atributo injetado como 'transient' (Atributo [{0}] na classe [{1}]).
... ...
impl/extension/jsf/src/test/java/test/Tests.java
... ... @@ -65,7 +65,6 @@ import br.gov.frameworkdemoiselle.internal.implementation.RedirectExceptionHandl
65 65 import br.gov.frameworkdemoiselle.internal.implementation.RedirectExceptionHandlerFactory;
66 66 import br.gov.frameworkdemoiselle.internal.implementation.SecurityObserver;
67 67 import br.gov.frameworkdemoiselle.internal.procuder.ParameterProducer;
68   -import br.gov.frameworkdemoiselle.internal.proxy.FacesContextProxy;
69 68 import br.gov.frameworkdemoiselle.template.AbstractEditPageBean;
70 69 import br.gov.frameworkdemoiselle.template.AbstractListPageBean;
71 70 import br.gov.frameworkdemoiselle.template.AbstractPageBean;
... ... @@ -113,7 +112,6 @@ public final class Tests {
113 112 .addClass(AuthorizationExceptionHandler.class)
114 113 .addClass(RedirectExceptionHandlerFactory.class)
115 114 .addClass(AbstractExceptionHandler.class)
116   - .addClass(FacesContextProxy.class)
117 115 .addClass(JsfBootstrap.class)
118 116 .addClass(ParameterProducer.class)
119 117 .addClass(AbstractPageBean.class)
... ...