jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: [527-InjectFacesContext] Support and review

From: Neil Griffin <neil.griffin_at_portletfaces.org>
Date: Thu, 16 Oct 2014 18:48:47 -0400

Hi Arjan,

Pleased to e-meet you, and sorry for the delay in responding.

The reason for the delay was because I decided to actually kick the tires and try @Inject FacesContext in a JSF portlet with Mojarra-2.3.0-m01-SNAPSHOT.

My test environment required that I make Weld and Mojarra compatible with plain Tomcat+Pluto which took a few days. But I am happy to report that @Inject FacesContext works! (more details below).

On Sep 25, 2014, at 5:56 PM, arjan tijms <arjan.tijms_at_gmail.com> wrote:

> Hi,
>
> On Thu, Sep 25, 2014 at 6:58 PM, Neil Griffin <neil.griffin_at_portletfaces.org> wrote:
> The JSF Portlet Bridge will make beans annotated with javax.faces.bean.RequestScoped survive from the ACTION_PHASE to the RENDER_PHASE.
>
> But CDI does not do that. If a JSF portlet developer annotates a bean with javax.enterprise.context.RequestScoped, then CDI creates a new bean in both the ACTION_PHASE and RENDER_PHASE.
>
> I have to admit I know almost nothing about Portlets, but if I understand correctly this is thus a general problem with javax.enterprise.context.RequestScoped and Portlets, and not specifically with injecting a request scoped FacesContext, right?

Actually it is not considered to be a problem with javax.enterprise.context.RequestScoped and *plain* Java Portlets. It's just the way things worked out since CDI was developed (primarily) with webapps in mind.

It's only a problem with javax.enterprise.context.RequestScoped and JSF portlets, when the portlet developer makes the assumption that it behaves the same way as javax.faces.bean.RequestScoped.

>
> But in this case would it really matter? If a single CDI request scope does not survive beyond the Portlet action phase and into the render phase, then there would simply be one additional call to FacesContext#getCurrentInstance if the proxy is referenced again in the render phase, right? This then grabs the current FacesContext according to the existing JSF rules and all should be right again. Or am I missing something obvious?

My tests indicate that you are 100% correct. When the proxy is referenced again in the RENDER_PHASE, the FacesContextProducer.create(CreationalContext) method is invoked and all is well.

>
> If there is a successor to JSR 329, then one of the requirements for that new JSR *might* be to re-define the behavior of javax.enterprise.context.RequestScoped.
>
> Just wondering, but isn't JSR 329 specifically designed for interoperability with JSF 1.2 only?

Although JSR 329 was designed for interoperability with JSF 1.2, 99% of the spec requirements and TCK tests apply equally well to JSF 2.x bridges. The spec requires that <managed-bean-scope>request</managed-bean-scope> exist from the ACTION_PHASE to the RENDER_PHASE.


Best Regards,

Neil

>
>
> On Sep 25, 2014, at 12:36 PM, Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:
>
>> Hi
>>
>> I know that the trick using @RequestScoped works, but
>> Is there a 1-1 relationship between FacesContext lifecycle
>> and the request lifecycle? That works fine on servlets but
>> it doesn't on portlets (action request / render request).
>>
>> It is possible to imagine other scenarios where this
>> assumption just fail. In my opinion, we should take the
>> long route, create a CDI scope and use that scope to
>> store the producer, so it get the right instance. After all
>> JSF should be in control of FacesContext lifecycle.
>>
>> regards,
>>
>> Leonardo Uribe
>>
>>
>> 2014-09-25 11:02 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:
>>> Hi,
>>>
>>> On Thu, Sep 25, 2014 at 4:32 PM, Edward Burns <edward.burns_at_oracle.com> wrote:
>>>> Arjan, can you take the action item to investigate this and report back
>>>> to the group? Such investigations and reports are the bread and butter
>>>> of expert group membership and really add significant value because the
>>>> results the produce are so actionable.
>>>
>>> I took a quick look, and the results are rather interesting.
>>>
>>> First of all, the feature is described here:
>>> http://docs.jboss.org/seam/3/servlet/latest/reference/en-US/html/injectablerefs.html#injectablerefs.http_servlet_request
>>>
>>> The producer was created by CDI wizards Dan Allen and Nicklas
>>> Karlsson, and for the HttpServletRequest it looks as follows:
>>>
>>> @Produces
>>> @Typed(HttpServletRequest.class)
>>> @RequestScoped
>>> protected HttpServletRequest getHttpServletRequest() {
>>> return holder.getHttpServletRequest();
>>> }
>>>
>>> See: http://grepcode.com/file/repository.jboss.org/nexus/content/repositories/releases/org.jboss.seam.servlet/seam-servlet/3.1.0.Beta2/org/jboss/seam/servlet/http/ImplicitHttpServletObjectsProducer.java?av=f
>>>
>>> The holder is an application scoped bean, which has as its main goal
>>> to collect and hold on to among others the HttpServletRequest via a
>>> thread local. Collection happens via a CDI event and the listeners
>>> stores the request object into TLS via a wrapper. Abbreviated it's:
>>>
>>> protected void requestInitialized(@Observes @Initialized final
>>> InternalServletRequestEvent e) {
>>> ServletRequest req = e.getServletRequest();
>>> // code omitted
>>> requestCtx.set(new HttpServletRequestContext(req));
>>> }
>>>
>>> See: http://grepcode.com/file/repository.jboss.org/nexus/content/repositories/releases/org.jboss.seam.servlet/seam-servlet/3.1.0.Beta2/org/jboss/seam/servlet/event/ImplicitServletObjectsHolder.java#70
>>>
>>> But the wrapper doesn't play a role in injection, since when the
>>> producer asks the holder for the request instance, it's unwrapped
>>> again. Abbreviated it's:
>>>
>>> public HttpServletRequest getHttpServletRequest() {
>>> // code omitted
>>> return HttpServletRequestContext.class.cast(requestCtx.get()).getRequest();
>>> }
>>>
>>> See: http://grepcode.com/file/repository.jboss.org/nexus/content/repositories/releases/org.jboss.seam.servlet/seam-servlet/3.1.0.Beta2/org/jboss/seam/servlet/event/ImplicitServletObjectsHolder.java#128
>>>
>>> So there's not a lot of magic going at all. The key seems to be that
>>> the producer itself is @RequestScoped, but the instance it produces
>>> doesn't seem to be a request scoped wrapper bean at all, just the
>>> normal instance. I do wonder a bit why they choose TLS storage instead
>>> of a request scoped bean, but that's beside the issue here.
>>>
>>> As JSF already stores the FacesContext in TLS, the entire holder
>>> construct isn't needed and seemingly the producer would only need to
>>> be annotated with @RequestScoped.
>>>
>>> Kind regards,
>>> Arjan
>
>