jakartaee / faces

Jakarta Faces
Other
99 stars 55 forks source link

Clarification: Firing of PostAddToViewEvent during Restore View Phase #1835

Open volosied opened 11 months ago

volosied commented 11 months ago

Section 2.2.1 of the Faces Spec says:

Using Application.publishEvent(), publish a PostAddToViewEvent with the created UIViewRoot as the
event source.

My understanding this event should only be fired when the request is not a postback. The JavaDoc is a bit clearer here: https://jakarta.ee/specifications/platform/9/apidocs/jakarta/faces/event/postaddtoviewevent

https://github.com/primefaces-extensions/primefaces-extensions/issues/517 discovered that the PrimeFacesScriptProcessor created JS scripts twice in MyFaces, but not Mojarra. MyFaces has this event fire during the Restore View phase, and Render View phase. Mojarra only it occur during the Render View phase. (Note: this is unrelated to the DuplicateIdException reported in 517)

MyFaces looks to behave incorrectly in practice, but it's contrary to the specification. What is correct here?

volosied commented 11 months ago

Looking at the spec issues, closest one I found was https://github.com/javaee/mojarra/issues/1387

volosied commented 11 months ago

@tandraschko Another thing I spotted: Spec says we should fire PostRestoreStateEvent, but I don't see MF do that in the restore view.

tandraschko commented 11 months ago

@volosied about PostRestoreStateEvent -> https://issues.apache.org/jira/browse/MYFACES-4625

tandraschko commented 11 months ago

@volosied no idea about the PostAddToViewEvent we should dig into Leos comments here: https://issues.apache.org/jira/browse/MYFACES-2638

tandraschko commented 11 months ago

here is also a old mail from Leo about it:

PostAddToView should be called only once, when the component is added
to the view.

But when the view is restored with PSS enabled, the initial view calls
PostAddToView, but the fact is if the algorithm is properly
implemented, you shouldn't notice anything, as it was implemented in
MyFaces. The reason of this behavior is the algorithm must ensure the
view is created doing exactly the same steps as when the view was
built by first time. PostAddToView can be used to create or add some
components to the component tree.

Remember that when PSS is disabled, the extra call does not happen.
But the user will not notice anything, things will work just the same.

The problem with PostAddToView is you need to call it exactly once,
because otherwise you could create duplicate components or have
problems like the one you described.

The problem is the state saving algorithm and facelets algorithm have
some side effects with PostAddToView. Facelets removes and adds
components to the tree, the state saving algorithm could trigger
component addition. So the algorithm must be carefully designed to
decide when and where to call it or not.

Why it works in MyFaces and doesn't work in Mojarra? I suppose it is
because the implementation is different. But in my opinion the right
behavior is the one implemented in MyFaces.

In conclusion, with PSS enabled, the extra call should be done, but
only when the initial view is built. After that, the view state must
be restored in a way that avoid any extra call to PostAddToViewEvent.
tandraschko commented 11 months ago

i think in general PostAddToViewEvent works fine for both Impls and normal components, which is also quite good documented in the javadoc.

The question is: when exactly is it required to fire the PostAddToViewEvent for the ViewRoot itself?

It seems Mojarra just does it once in FaceletViewHandlingStrategy#buildView, without any conditions.

MyFaces does it in RestoreViewExecutor, when it's not a postback and in FaceletViewDeclarationLanguage#buildView when its NOT refreshTransientBuild