Gang -
Remember like 10 months ago we had an expert group meeting where I
happily volunteered to handle several action items? [1] Er. About that…
guess I blew it on the "action" part. (Sorry!) But no time like the
present, right?
One of my action items:
> 4. PostRestoreStateEvent is not published using application.publishEvent
>
> Action: needs clarification. I don't think publishEvent can be used.
>
> => andy schwartz
Was the result of a question that Leonardo raised back in the old
jsr-314 days [2]:
> Just one question: why PostRestoreStateEvent is not published using
> Application.publishEvent?.
>
> This event is used to update component bindings on beans. The only mention
> on the spec is on JSF 2.0 spec (not rev A) UIViewRoot.processRestoreState,
> but that code was changed to be called on restore view phase.
>
> The final effect is you can't suscribe listeners to this event, which
> is odd
> because there is nothing on the spec or javadoc that says this event can't
> be intercepted by a listener. It is just in practice when you find both
> Mojarra and MyFaces do the same (because this behavior comes from the
> description on UIViewRoot.processRestoreState).
>
> regards,
>
> Leonardo Uribe
Although I was not involved in either the MyFaces/Mojarra implementation
work on this feature, I suspect I know why both teams chose to call
UIComponent.processEvent() directly rather than call
Application.publishEvent().
Leonardo mentioned one unusual requirement that is specific to
PostRestoreStateEvent:
> This event is used to update component bindings on beans.
As a result of this requirement, PostRestoreStateEvents must be
delivered to *all* UIComponent instances, regardless of whether the
component happens to have any listener registered. Calling
UIComponent.processEvent() was simply the most efficient way to ensure
that the "binding" attribute would continue to function correctly. The
downside of this, as Leonardo pointed at, is that PostRestoreStateEvent
listeners registered by the app are not honored.
The "correct" approach would have been to:
1. Require that UIComponent.getListenersForEventClass() always return a
non-empty list that minimally contains the UIComponent instance itself.
And...
2. Call Application.publishEvent() instead of UIComponent.processEvent().
The problem with #1 is that this would either require increasing the
amount of storage for every UIComponent instance (bad) or increasing the
amount of transient memory used when delivering PostRestoreStateEvents
(also bad).
We could avoid this by spec'ing that during PostRestoreStateEvent
delivery, both UIComponent.processEvent() and Application.publishEvent()
must be called. This would ensure that both component bindings are
re-established *and* any registered listeners are called.
A problem with #2 is that Application.publishEvent() is slow.
Fixing PostRestoreStateEvent (by adding a call to
Application.publishEvent()) is likely the right thing to do, at least
from a spec consistency/sanity perspective. However, this will add new
overhead, so we should tread carefully here (and ideally do some
performance testing).
Andy
[1]
http://java.net/nonav/projects/javaserverfaces-spec-public/lists/jsr344-experts/archive/2011-04/message/51
[2]
http://lists.jboss.org/pipermail/jsr-314-open-mirror/2011-March/003234.html