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

[jsr372-experts] Re: [jsr372-experts mirror] JSF API to extract component state from view state, and to physically remove view state from server side state

From: Bauke Scholtz <balusc_at_gmail.com>
Date: Thu, 21 Jul 2016 20:05:31 +0200

Hi,

1. The technical reason that I'd like to restore UIViewRoot's state is
being able to properly invoke all listeners associated with
the PreDestroyViewMapEvent. To the point, only restoring the component's
own state (preferably only those listeners) is sufficient for the task of
OmniFaces @ViewScoped, not restoring the whole tree.

2. The PreDestroyViewMapEvent already deals with destroying view map and
associated view scoped beans. Only the server side view state remains in
memory. Client side view state is not a problem. The main goal is
immediately destroying view scope map and beans. As to inactive views,
that's exactly why OmniFaces @ViewScoped uses the unload trick for this and
this indeed sends a command through synchronous ajax. The
ViewHandler#restoreView() could be used instead, but this implicitly also
invokes buildView() which is unnecessarily expensive for the purpose of
only firing the PreDestroyViewMapEvent. The alternative would be extracting
buildView() step from the restoreView() method into a separate method.

Cheers, B


On Thu, Jul 21, 2016 at 7:19 PM, Leonardo Uribe <leonardo.uribe_at_irian.at>
wrote:

> Hi
>
> About 1.
>
> UIViewRoot is an special component that requires some steps to be
> restored, but I'm not sure if that's required outside the state saving
> algorithm.
>
> I think the reason you need to restore the UIViewRoot is to have a
> reference to a view, so you can destroy it later, right? If that so, the
> problem is another different one.
>
> In MyFaces restore the UIViewRoot is a complex task, because UIViewRoot
> not only holds state related to the component itself, but also information
> about the tree structure (FaceletState and component id counters) and
> viewScope bindings. It started with restoreState(...), but now there are a
> lot of lines of code to restore it properly.
>
> About 2.
>
> In MyFaces there a CDI interface to deal with views called
> ViewScopeProvider. There is a method called onSessionDestroyed() and
> another one called destroyViewScopeMap(facesContext,viewScopeId) which
> deals with the problem.
>
> On server side state saving, the algorithm applies some logic to remove
> the stored view states that are not being used, and use the SPI api to
> remove the associated viewScope if necessary.
>
> But please note the big problem is not the current view, but the inactive
> views that needs to be removed and their association with CDI (because
> there is no UIViewRoot instance to grab them). ViewScopeProvider SPI
> interface helps to fill the gap between the view state and the CDI.
>
> This is considered an implementation detail, so we don't really need
> anything from spec perspective. But there is nothing when client side state
> saving is used.
>
> Remember there was a change in the spec where ViewScope is now stored in
> the server only, so when client side state saving is used, there is no way
> to clean the scope, because we don't have the API to do it. So, a possible
> use case I can imagine is, if we have something to detect when a window or
> tab has been closed on the client, we could send a message to the server
> and with the api we could clear the scope.
>
> In conclusion an API to remove the view state or the associated viewScope
> state has sense to me, but I would like to see the possible scenarios where
> this API could be useful. I have only identified one use case, but it looks
> that it requires something to send a command through ajax.
>
> regards,
>
> Leonardo Uribe
>
> 2016-07-21 8:29 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:
>
>> Hi,
>>
>> During working on "immediately destroy bean instance and server side view
>> state on page unload" feature of OmniFaces @ViewScoped, I stumbled upon two
>> shortcomings in public JSF API.
>>
>>
>> 1. There is no clean way to restore only the state of a specific
>> component. The ResponseStateManager#getState() returns the entire view
>> state while I'd like to restore only the component state of UIViewRoot
>> instance itself. See also
>> https://github.com/omnifaces/omnifaces/blob/da3847ff41f93e2a4f847eb2176c2343a32b968b/src/main/java/org/omnifaces/viewhandler/OmniViewHandler.java#L141
>> In other words, there is no JSF API provided way to obtain exactly the part
>> of the view state as expected by 2nd argument of
>> UIComponent#restoreState().
>>
>> I'm only not exactly sure if adding a public API on that would be a great
>> idea. Perhaps we should leave it, but just throwing here for thoughts.
>>
>>
>> 2. There is no JSF API provided way to physically remove the entire view
>> state from the server side state. See also:
>> https://github.com/omnifaces/omnifaces/blob/296c4d03f47a8d69360f14ef74c5d6e3fe243ff6/src/main/java/org/omnifaces/util/Hacks.java#L362
>>
>>
>> I'd expect to see a ResponseStateManager#destroyViewState() or
>> #removeViewState() taking FacesContext argument which does exactly the task
>> of destroying/removing the server side view state associated with the
>> currently set view root. This could also be called by the implementation
>> directly after PreDestroyViewMapEvent, just for more optimal memory usage,
>> and also a more robust LRU sequence of view states in Mojarra.
>>
>>
>> What do you guys think?
>>
>> Cheers, B
>>
>
>