Using a simplified version of the progress bar example, we can see the unique treatment of View-scoped beans in MyFaces. I instrumented the constructor of the OutputProgressController (annotated with View scope) as well as added logging to a PostConstruct method:
The first time it is needed, the OutputProgressController is created and the PostConstruct method is called as expected:
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController: constructor called for org.icefaces.demo.basic.progress.OutputProgressController@787f189
@javax.faces.bean.ManagedBean(name=outputProgressController, eager=false)
@javax.faces.bean.ViewScoped()
OutputProgressController.afterConstruction: org.icefaces.demo.basic.progress.OutputProgressController@787f189
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-69,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@787f189
During the next lifecycle which is caused by clicking the button to start Timer task, you can see the instance has a different hashcode but we've not been instructed that a new instance has been created. This is the reference the timer task will always have:
INFO: BEFORE INVOKE_APPLICATION(5) from /compat-basic/progress.jsf
OutputProgressController.setPercentComplete:
thread : Thread[Timer-14,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@e27fdb9
29-Aug-2011 10:08:37 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER INVOKE_APPLICATION(5) from /compat-basic/progress.jsf
29-Aug-2011 10:08:37 AM org.icefaces.impl.util.DebugPhaseListener beforePhase
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-71,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@e27fdb9
29-Aug-2011 10:08:37 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER RENDER_RESPONSE(6) from /compat-basic/progress.jsf
During the next lifecycle, we get the percent vvalue from an instance that has yet another different hashcode:
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-71,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@63b6feb1
29-Aug-2011 10:08:37 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER RENDER_RESPONSE(6) from /compat-basic/progress.jsf
The next lifecycle, we see yet another "instance" but the timer thread is setting the percent complete on a previous instance:
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-71,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@3d3d2941
29-Aug-2011 10:08:38 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.setPercentComplete:
thread : Thread[Timer-14,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@e27fdb9
Again, we are getting from what appears to be a different instance:
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-72,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@25bf26fe
29-Aug-2011 10:08:39 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER RENDER_RESPONSE(6) from /compat-basic/progress.jsf
Getting from a new instance but setting on the one that the Timer task originally had a reference to:
INFO: BEFORE RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.getPercentComplete:
thread : Thread["http-bio-8080"-exec-72,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@64699c99
29-Aug-2011 10:08:40 AM org.icefaces.impl.util.DebugPhaseListener afterPhase
INFO: AFTER RENDER_RESPONSE(6) from /compat-basic/progress.jsf
OutputProgressController.setPercentComplete:
thread : Thread[Timer-14,5,main]
controller: org.icefaces.demo.basic.progress.OutputProgressController@e27fdb9
This mismatch between the instance that the Timer task has a reference to and the one that the requests are getting the value from continues and explains why the updates to the client never change the value - they are always '0', the default value of a new bean.
I've checked in a fix to the core that uses a SystemEventListener to modify the h:commandLink but only when running with MyFaces and an ICEfaces view.
The patch listens for commandLinks and, if there are no AjaxBehaviors associated with the commandLink, it adds one. This causes MyFaces to detect that Ajax is in plan and render out the correct handler.