[jsr-314-open-mirror] [jsr-314-open] Fix UIData state saving model (issue 153)

Leonardo Uribe lu4242 at gmail.com
Fri Mar 19 13:27:06 EDT 2010


In short, this topic is an attempt to add full state to components inside
UIData. I'll do a brief resume, so people can understand this one easily.

UIData uses the same component instances to render multiple rows. Suppose
this example:

<h:dataTable id="cities" var="city" value="#{country.cities}">
    <h:column>
        <h:outputText value="#{city}"  />
    </h:column>
</h:dataTable>

In the component tree it is created this hierarchy:

HtmlDatatable
  UIColumn
    HtmlOutputText

If we have 10 cities, the same component is used over and over to render all
10 cities. The reason to do that in this way is keep state as small as
possible.

Now let's suppose something like this:

<h:dataTable id="cities" var="city" value="#{country.cities}">
    <h:column>
        <h:inputText value="#{city}"  />
    </h:column>
</h:dataTable>

It was changed the output component for an input one. If this table is in a
form and the values are submitted, the same component is used to apply
request values, validate and apply them to the model (update process). To
make this possible, UIData class has some code to preserve this values
between phases (using EditableValueHolder interface), so when each phase is
processed, all rows are traversed and you get the expected behavior.

Now suppose something more complex: We have a code that use
invokeOnComponent to change the style of my inputText. In theory, only one
row should change. But in fact, all rows are rendered with the same color.
Why? because we use the same component to render all rows, and we don't
preserve the children component state between rows.

There is a lot of issues, questions, and side effects related to this issue,
but just to put some of them here:

TOMAHAWK-1062 InputTextArea doesn't work properly inside facet DetailStamp
TOMAHAWK-96 Data table Scroller not working the dataTable which was actually
contained in other DataTable
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=153Problems
with UIData state saving

Also, it is well know that one reason why people uses c:forEach in facelets,
is because this one create "full" components per each row. It is very easy
to find articles on internet.

Now, with jsf 2.0 we have partial state saving, so we have a chance to fix
this one once and for all. I tried fix this one per months (maybe years!),
but talking with Martin Marinschek on JSFDays, some ideas came out and
finally it was found a possibility to fix this one using the existing api
and with little changes on the spec.

The proposal is this:

1. Do not call UIComponent.markInitialState() on
ComponentTagHandlerDelegate, as ComponentHandler javadoc says, instead call
it after PostAddToViewEvent are published on vdl.buildView(). We need to
call it from root to nodes, so the parent component is marked first. I know
the place where this call comes is from trinidad tag handler, but this call
needs to be fixed in a more predictable way.
2. Use an attribute on facesContext to identify when the VDL is marking the
initial state (in myfaces there is already an attribute called
"org.apache.myfaces.MARK_INITIAL_STATE"). This is necessary to indicate
UIData instances that it is time to save the full state of all component
children,
3. Allow UIData to hold a map where the key are client ids and the value are
the deltas of all components per row. This map should be saved and restored.
4. Change UIData.setRowIndex() to restore and save the component state.

I'll attach a patch on myfaces issue tracker with the algorithm proposed
(because it is based on myfaces codebase). It was tested and it works. But
note it is necessary to fix the javadoc for UIData.markInitialState(),
ComponentHandler and maybe vdl.buildView(), so the intention is propose this
change for jsf 2.0 rev A. Note this works only with PSS enabled because
without it we don't have a place to notify UIData instances that it is
necessary to get the full state. Also, note this patch preserve backward
compatibility, because the old way to store/save is applied after the full
state is restored.

Really, I have the strong temptation to apply some similar code on myfaces
UIRepeat component (because this class is private), but I prefer first ask
to EG to know what you guys think about it.

Suggestions are welcome,

regards,

Leonardo Uribe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jsr-314-open-mirror/attachments/20100319/c92050e6/attachment-0003.html 


More information about the jsr-314-open-mirror mailing list