[
https://issues.apache.org/jira/browse/MYFACES-4047?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15290362#comment-15290362
]
Leonardo Uribe commented on MYFACES-4047:
-----------------------------------------
The patch has some observations we need to discuss. Let me tell you the whole
story, I know it could be repetitive somehow but it is important to understand
how solve this properly.
In JSF 2.0, javax.faces.event.PreDestroyViewMapEvent was added with this
description in the javadoc:
"... This event must be published by a call to
Application.publishEvent(javax.faces.context.FacesContext, java.lang.Class,
java.lang.Object) when the clear method is called on the map returned from
UIViewRoot.getViewMap(). ..."
The idea in that time, was to provide an event that can be used to handle
@PreDestroy annotations for view scope.
But the implementation was not perfect. JSF 2.0 spec section 5.4.1 says "... in
the case of a managed bean placed in view scope, methods annotated with
@PreDestroy must only be called when the view scope is destroyed. See the
javadoc for FacesContext.setViewRoot(). ..."
The key point is FacesContext.setViewRoot(...) is usually called from
NavigationHandler.handleNavigation(...), mostly because this is the point where
you can be 100% sure the view is discarded. So, deep inside setViewRoot(...)
there is a call that invokes viewMap.clear() and the implementation of ViewMap
(in that time it was located in UIViewRoot) publish PreDestroyViewMapEvent and
since there is a listener (ManagedBeanDestroyer) subscribed to that event, the
managed beans on view scope were destroyed.
But in JSF 2.2 things changed, because it was specified. The related issue is:
https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-905
But in JSF 2.2 section 5.4 there is a line that says: "... The annotations in
the package javax.faces.bean will be deprecated in a version of the JSF
specification after 2.2. Therefore, developers are strongly recommended avoid
using those annotations and instead use the ones from Java EE 6. ..."
So, in MyFaces the code was let as it was in JSF 2.0/2.1 and focus on CDI
implementation of view scope, so PreDestroy works there on session expiration.
But looking now on some comments in JAVASERVERFACES_SPEC_PUBLIC-905, it looks
the behavior was implemented in the RI for both cases.
Now, the problem with the patch proposed is that it does not follow the
convention, publish PreDestroyViewMapEvent and then let the listener attached
to that event to their job. Instead, it calls directly the listener.
There is a class called org.apache.myfaces.view.ViewScopeProxyMap that works as
a "middle man" class that allows to switch between implementations (default or
CDI). There you can see this lines on clear() implementation:
{code:java}
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getApplication().publishEvent(facesContext,
PreDestroyViewMapEvent.class, facesContext.getViewRoot());
{code}
Instead call LifecycleProvider.destroyInstance(...), try use this call. The
problem is onSessionDestroyed() could be called from locations where there is
no valid FacesContext instance (ex: session invalidation), so in this case, if
there is no FacesContext instance, you need to create a custom context in the
same way as in ViewScopeBeanHolder is done (but it is a bit tricky because you
need a reference to servletContext, and the problem is how to get it, maybe
pass it as a param from DefaultViewScopeProviderFactory).
> @PreDestroy method not invokved on javax.faces.bean.ViewScoped beans on
> Session invalidation
> --------------------------------------------------------------------------------------------
>
> Key: MYFACES-4047
> URL: https://issues.apache.org/jira/browse/MYFACES-4047
> Project: MyFaces Core
> Issue Type: Bug
> Components: JSR-344
> Affects Versions: 2.2.10
> Reporter: Paul Nicolucci
> Priority: Minor
> Attachments: myfaces-4047.patch
>
>
> Consider the following scenario:
> Bean1:
> @Named
> @ViewScoped (javax.faces.view.ViewScoped)
> Bean2:
> @ManagedBean
> @ViewScoped (javax.faces.bean.ViewScoped)
> When the session is invalidated the
> org.apache.myfaces.cdi.impl.CDIManagedBeanHandlerImpl.onSessionDestroyed()
> method is invoked. Here, MyFaces destroys all of the
> javax.faces.view.ViewScoped @Named beans and @PreDestroy is invoked on these
> beans. However, the @ManagedBean /ViewScoped bean does not have its
> @PreDestroy invoked.
> I believe this is because the assumption was made that if an Application is
> CDI enabled it will contain all CDI @Named beans and not any @ManagedBeans.
> There is also the DefaultViewScopeHandler which is not yet implemented for
> "onSessionDestroyed" that would be used in the case when CDI is not enabled,
> that is when only @ManagedBeans are contained in the application.
> I believe it is possible to update the CDIManagedBeanHandlerImpl to be aware
> of the ViewScoped ManagedBeans and destroy them onSessionDestroy first by
> just getting the viewMap and iterating over the entries as we do when the
> PreDestroyViewMapEvent is processed.
> I'd like to use this issue to resolve the problem in
> CDIManagedBeanHandlerImpl as well as implement onSessionDestroy in
> DefaultViewScopeHandler.java
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)