0

When using Web Flow (2.3.1.RELEASE) in combination with JSF, I have a rendering problem when using a composite component of any kind and e.g. an <h:outputLabel /> component on 1 page after clicking a <h:commandLink />. The contents of the composite component are always displayed at the bottom of the page! When refreshing the page, rendering is fine again...

I can very easily reproduce this using this code:

My facelet:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:test="http://java.sun.com/jsf/composite/components">

<h:body>
<h:form id="form">

<h:commandLink id="link" value="link" /><br/>
<test:testComponent id="test" />
<h:outputLabel value="label" id="label" />

</h:form>
</h:body>
</html>

The composite component:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface>
</composite:interface>

<composite:implementation>
<h:outputText value="hello world" />
</composite:implementation>

</ui:composition>

My suspicion is that the ordering of components is messed up when Web Flow restores the view after resuming the flow. When using the above code in a simple JSF facelet (without using Web Flow), all is working fine.

I've debugged through the internals of Mojarra and Web Flow and can see that the order is being mixed in the buildView(FacesContext ctx, UIViewRoot view) method of FaceletViewHandlingStrategy when using Web Flow and not when using plain JSF.

I have posted this very same issue on the Spring forum and Spring JIRA, but there has not been a lot of reply.

I would like to thank anyone in advance who takes a look at this problem!

2 Answers2

0

Have you tried adding this to the MVC servlet context XML?

  <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" >
            <webflow:flow-execution-attributes>
                <webflow:redirect-in-same-state value="false"/>
            </webflow:flow-execution-attributes>

    ....
    </webflow:flow-executor>
rootkit
  • 2,165
  • 2
  • 29
  • 43
  • Great answer. Now I only have to look what the other side effects of this solution are, but it does pass the initial test ! So thank you, very much :) –  Jan 18 '13 at 13:42
  • SWF breaks Primefaces partial rendering unless redirect-in-same-state is set to false. There is an obscure reference of this setting in Spring docs, see http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch13s10.html but it doesnt mention anything about partial rendering. I am developing webapp with PF and SWF, have this set to 'false' and havent noticed any side effects. Glad it helped, and good luck! – rootkit Jan 18 '13 at 17:06
  • Well, it does seem to render browser warnings (e.g. form resubmitting) in some given situations, but that's not taking anything away from the solution. Nice find! –  Jan 21 '13 at 10:01
0

The SpringSource Team solved this issue:

It seems like the main cause of this issue is the com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.adjustIndexOfDynamicChildren(). Adding a conditional breakpoint (on parent instanceof UIForm) shows how the child order is changed. It appears that com.sun.faces.context.StateContext is tracking dynamic changes via a SystemEventListener inner class. The listener is added to the UIViewRoot when startTrackViewModifications is initially called. There seems to be a mismatch between listener used when the 1st postback is received and the one used after the redirect: Postback is received JSF View is restored and startTrackViewModifications starts Event are processed A redirect is issued The redirect GET is received The JSF View is restored but the previous StateContext$AddRemoveListerner appears to already be attached There are now two StateContext in play, a new one that gets added and the previous one referenced via the AddRemoveListerner Calls to startTrackViewModifications now only update the newer StateContext In order to fix the issue we need to ensure that the StateContext.release() method is called before the redirect. This method will trigger unsubscribeFromViewEvent on the UIViewRoot. It seems that StateContext.release() is only called via StateManagerImpl.saveView. Since Spring Web Flow has its own statemanagement this method is currently not always called.

Courtesy of Phil Webb

  • That explains the cause. Perhaps it's worth mentioning that this has been fixed in Spring Web Flow 2.4.0 M1 release - at least according to Spring Jira. – rootkit Feb 05 '13 at 16:43