[ 
https://issues.apache.org/jira/browse/MYFACES-2638?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12873795#action_12873795
 ] 

Michael Kurz commented on MYFACES-2638:
---------------------------------------

Added test webapp for potential problem with this solution.

> Fix PostAddToViewEvent and PreRemoveFromViewEvent publishing conditions
> -----------------------------------------------------------------------
>
>                 Key: MYFACES-2638
>                 URL: https://issues.apache.org/jira/browse/MYFACES-2638
>             Project: MyFaces Core
>          Issue Type: Bug
>          Components: JSR-314
>    Affects Versions: 2.0.0-beta-3
>            Reporter: Leonardo Uribe
>            Assignee: Leonardo Uribe
>         Attachments: MYFACES-2638-3.patch, MYFACES-2638-4.patch, 
> MYFACES-2638-6.patch, MYFACES-2638-6_1.patch, MYFACES-2638-6_5.patch, 
> MYFACES-2638-6_8.patch, MYFACES-2638-test-webapp.zip
>
>
> From a discussion of jsr-314-open mailing list:
> Actually the event publishing conditions of 
> PostAddToViewEvent/PreRemoveFromViewEvent are not very clear. These 
> conditions depends if partial state saving is used or not and if facelets 
> updates the view or  not. The problem is this fact is not very intuitive, so 
> for write code correctly the user needs to be aware of that, in other words 
> this should be documented somewhere. Also, there are some technical questions 
> that could be of interest on this mailing list and myfaces dev list too.
> In theory, PostAddToViewEvent is used in this cases:
> - h:outputScript and h:outputStylesheet renderers uses it to relocate 
> component resources to UIViewRoot facet "head" or "body" target 
> (h:outputStylesheet by default to "head"). Note "head" and "body" facets are 
> transient.
> - cc:insertChildren and cc:insertFacet, to relocate components to some place 
> inside cc:implementation. The reason why we do that through a listener 
> attached to PostAddToViewEvent is we need to take into account the case of 
> nested composite components using cc:insertFacet/cc:insertChildren. Note when 
> the component tree is built the first time, PostAddToViewEvent is propagated 
> from root to nodes.
> - When Partial State Saving is enabled, it is necessary to attach a listener 
> to PostAddToViewEvent/PreRemoveFromViewEvent, so if some user add/remove a 
> component, we can keep track of those changes and save/restore the component 
> tree properly, in other words, support component addition or removal 
> programatically.
> Now, the instants of time where PostAddToViewEvent is published are:
> - With Partial State Saving enabled
>    * When the view is build at first time.
>    * In a postback when the view is build but before the state of the 
> component is restored.
> - With Partial State Saving disabled
>    * When the view is build at first time.
>    * In a postback when the view is "refreshed", because all component nodes 
> are detached and attached to the tree. In other words, on render response 
> phase, vdl.buildView is called and in this case facelets algorithm add all 
> transient components (usually all html markup not saved), and to do that, it 
> detach and attach all components to be in right order. This also has some 
> other implications, like c:if tag depends on this to work correctly.
> A developer that is not aware of this fact could think that 
> PostAddToViewEvent is called when the view is build.
> This is true with PSS is enabled, but is not true when PSS is disabled. On 
> this topic:
> [jsr-314-open] add component resources depending on the owner component state
> It was described why PostAddToViewEvent cannot be used in that case. But 
> let's change a litte bit the problem. We have a custom component that creates 
> some other on PostAddToViewEvent and add it as a children. It should work but 
> in fact it only works when PSS is enabled, with PSS disabled that code will 
> cause a duplicate id exception. Of course, the developer can solve it with 
> some effort but the point is we are not consider the element of least 
> surprise.
> But this fact this is only the tip of the iceberg. In mojarra (this was 
> already fixed on myfaces), components relocated by cc:insertChildren or 
> cc:insertFacet does not have state when PSS is disabled, because when the 
> view is "refreshed" the components are created again, but facelets algorithm 
> remove all components with no bound to a facelet tag handler, and then the 
> listeners attached to PostAddToViewEvent relocates the new ones, so this 
> effect is not notice at first view.
> Do you remember PostAddToViewEvent propagation ordering is important by 
> cc:insertChildren/cc:insertFacet? well, with PSS disabled, the ordering now 
> is from nodes to root, because all nodes are detached and attached from nodes 
> to root, so in myfaces we did something like this (I removed some non 
> relevant code to be more clear):
>         try
>         {
>             if (refreshTransientBuild)
>             {
>                 context.setProcessingEvents(false);
>             }
>             // populate UIViewRoot
>             _getFacelet(renderedViewId).apply(context, view);
>         }
>         finally
>         {
>             if (refreshTransientBuild)
>             {
>                 context.setProcessingEvents(true);
>                
>                     // When the facelet is applied, all components are 
> removed and added from view,
>                     // but the difference resides in the ordering. Since the 
> view is
>                     // being refreshed, if we don't do this manually, some 
> tags like
>                     // cc:insertChildren or cc:insertFacet will not work 
> correctly, because
>                     // we expect PostAddToViewEvent will be propagated from 
> parent to child, and
>                     // facelets refreshing algorithm do the opposite.
>                     
> FaceletViewDeclarationLanguage._publishPreRemoveFromViewEvent(context, view);
>                     
> FaceletViewDeclarationLanguage._publishPostAddToViewEvent(context, view);
>             }
>        }
> In few words, disable event processing, and fire PostAddToViewEvent and 
> PreRemoveFromViewEvent in the expected order to build the tree correctly. If 
> we don't do this, h:outputScript and h:outputStylesheet will not work 
> correctly (remember that UIViewRoot "head" and "body" facets are transient, 
> so if these components are relocated, are in fact transient too). Also, care 
> must be taken to prevent the listener of programatic component 
> addition/removal register components on this time.
> The conclusion based on this reasoning, it is clear the need of new event 
> that be specific for relocate components (keep it simple for christ sake!). 
> This event should be propagated for all components in the tree after the view 
> is build from root to nodes. It could be good to have some clearification 
> about the real intention of PostAddToViewEvent/PreRemoveFromViewEvent. 
> Really, better names for those events are 
> PostAddToComponentTreeEvent/PreRemoveFromComponentTreeEvent.
> I'll attach a proposal to fix this one soon.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to