Hi Gavin,

I'll skip over/ignore some aspects (like capturing user typed form updates & 
actions), and concentrate on the core issue. I'll also try to keep it simple, 
for the benefit of anybody else reading. Whilst I'm talking here about Seam of 
course, I'd like to be clear to people that it's not a problem with Seam - 
rather something Seam can feel the impact of & also help overcome.

For a component like this in a view:

<h:commandButton disabled="#{!projectFinder.listOK}" />

JSF uses the #{!projectFinder.listOK} binding twice. Once during the 
RENDER_RESPONSE phase for determining component render style, then again when 
JSF rebuilds the component tree. This enables JSF to restore the view then 
generate a detected event, as if the UI was sitting in memory the whole time. 
It happens during APPLY_REQUEST_VALUES, where a call is made to 
UIViewRoot.processDecodes.

Here's the JSF1.2-b16 implementation call stack from the second use of the 
value binding.  I believe from looking at the MyFaces source, that the same 
would happen there:

$Proxy97.isListOK() line: not available
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available 
[native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 585
BeanELResolver.getValue(ELContext, Object, Object) line: 218
FacesCompositeELResolver(CompositeELResolver).getValue(ELContext, Object, 
Object) line: 135
FacesCompositeELResolver.getValue(ELContext, Object, Object) line: 58
AstValue.getValue(EvaluationContext) line: 96
AstDeferredExpression.getValue(EvaluationContext) line: 25
AstCompositeExpression.getValue(EvaluationContext) line: 30
ValueExpressionImpl.getValue(ELContext) line: 183
TagValueExpression.getValue(ELContext) line: 71
HtmlCommandButton.isDisabled() line: 169
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available 
[native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 585
UIComponentBase$AttributesMap.get(Object) line: 1525
Util.componentIsDisabledOrReadonly(UIComponent) line: 572
ButtonRenderer.decode(FacesContext, UIComponent) line: 108
HtmlCommandButton(UIComponentBase).decode(FacesContext) line: 791
HtmlCommandButton(UIComponentBase).processDecodes(FacesContext) line: 1012
HtmlForm(UIForm).processDecodes(FacesContext) line: 203
UIViewRoot(UIComponentBase).processDecodes(FacesContext) line: 1007
UIViewRoot.processDecodes(FacesContext) line: 499
ApplyRequestValuesPhase.execute(FacesContext) line: 101

The end result for a JSF app is that the #{!projectFinder.listOK} binding 
referenced on "viewX" must be available during the handling of any action event 
generated from "viewX". Because "projectFinder" was destroyed at the end of the 
last web request, a new instance of "projectFinder" will be created during the 
evaluation of the #{!projectFinder.listOK} binding.

This new instance will be a default initialized bean (or component in the case 
of Seam), which leads to an invalid restoration of view state. In the example 
of projectFinder in this thread, which is from the issue example (plus isListOK 
method), the projectList will be set to null - and then be outjected over the 
top of the projectList value we want to keep.

What many JSF developers seem to be after (a hunch), is a way to keep their 
backing beans around to service the binding evaluations during view 
reconstruction. It seems a lot are resorting to session scope (but will then 
have trouble if they need multiple instances of course). Seam might be able to 
get round this with style.

The quick-fix solution, as I posted here, is to outject a listOK Boolean to 
page scope, and change view references to #{listOK}. Because it's page bound, 
the view reconstruction will be able to get it's value despite the component 
that created it being destroyed. Also, avoid heavy business logic in bound 
method - do that in the action & set up info that getters can access simply 
from other lifecycle phases.

It would be great though if Seam components themselves could be destroyed 
later, so that the component tree can be rebuilt from the correct instance. 
There would be a cost to holding/tracking the instance, but savings also. For 
example, projectList might be built again from db after it gets nulled out, 
even though we end up with an invalid state for the new projectFinder instance.

The "component lifetime & usage lifetime" mismatch is not just for EVENT scope, 
but for other scopes too. Page fortunately offers a way around it. I'm new to a 
lot of the tech in this stack, and it would be good to be told I'm wrong about 
this stuff, but I don't think so. Thoughts?

View the original post : 
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3933976#3933976

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3933976


-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
JBoss-user mailing list
JBoss-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to