jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: Improvements for ajax update (related to Handling Focus after Ajax update)

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Wed, 22 Jun 2016 15:07:17 +0200

Hi

I have checked BabbageFaces and well, I have seen that before on IceFaces
Direct-to-DOM Rendering.

Both solutions faces the same challenges. High CPU and Memory usage is
exchanged by less bytes exchanged over the network. At the end there is a
trade-off.

This is what I "think" or "believe" based on my own experiments over
performance in JSF (MyFaces). I put my own opinions in doubt because you
can't really be 100% sure until you run a proper test, and I have seen
sometimes in reality things are different.

A DOM tree in memory will be bigger than a JSF component tree. Calculate
the difference means calculate two DOM trees before and after and then do a
full traverse over the tree. Calculate one DOM tree is equivalent to render
a view and that takes around 70% of the time spent by JSF lifecycle (in
fact most of the lifecycle is cheap compare with render the view, which is
the real work that you can't avoid). So, based on this reasoning, we can be
sure any ajax request will take 2.5 or 3 times more than a single request,
and we'll use 3 times or more memory.

It is worth? Yes, it could be, because at the end there are other things
that weight more like resource caching, database access and so on, so if
you have enough CPU and Memory this could be helpful. But I think we could
skip the DOM comparison and use the JSF component tree, which already have
PSS and we can use it to calculate the difference and have the same effect
without spend so many resources. The problem is to do that, we need to
change the spec a bit. The strategy using a DOM comparison algorithm can be
done without spec changes.


The central point to remember (and to summarise) is the current API right
now is not flexible enough to implement this idea because the component
cannot decide how to render itself on a partial/ajax request. Fortunately
there is a solution that we can do for JSF 2.3 and it is add this method to
UIComponent / Renderer:

public void encodePartial(FacesContext context, PartialResponseWriter
prwriter)

(encodePartial is better name than encodeAjax).

There are a lot of use cases:

- Add javascript/css using prwriter.startEval(...) that could require the
component to work.
- Simplify ajax update if only one or two attributes has changed (ok we
can't change attributes bound to event listeners but once the view is built
how often do they really change?).
- Execute an script to load some information in the component (embed JSON,
update the state, set a flag, ...).

This is in fact a "refactoring", because the idea is just stop thinking of
a component as a bunch of html code "without mind" on the client and
instead think of it as something you can "communicate" from the server.

But in that sense, encodePartial(...) is still not enough because what this
method is saying is "... update yourself because an ajax request requires
to do so, choose what do you need to do ...". The next step is the
component from the client could say "... I need just some info (in JSON?)
..." and the component counterpart on the server could say "... here it
is, take it ...". There is an small semantic difference between both steps,
because in the second one you are sending an "indication" or "param"
specific to the component that indicates how the request should be
processed, but then you expect some script or callback to be called so the
data can be processed by the same component counterpart on the client.

regards,

Leonardo


2016-06-21 21:25 GMT+02:00 Bauke Scholtz <balusc_at_gmail.com>:

> Hi,
>
> Have you already looked at BabbageFaces?
>
> Blog:
> http://www.beyondjava.net/blog/introducing-babbagefaces-efficient-ajax-dirt-cheap
> Demo: https://www.angularfaces.net/babbageFaces
> Github: https://github.com/stephanrauh/BabbageFaces
>
> Cheers, B
>
>
> On Thu, Apr 16, 2015 at 7:51 AM, Leonardo Uribe <leonardo.uribe_at_irian.at>
> wrote:
>
>> Hi
>>
>> KM>> Thanks for the detailed explanation; I like what you're
>> KM>> proposing for partial updates; you have provided the
>> KM>> implementation details of the JSON rendering feature
>> KM>> I mentioned at JavaOne, except without JSON, of
>> KM>> course (which is fine)
>>
>> Yes, that's the idea. Just provide some more concrete ideas
>> about what to do and how.
>>
>> I just wanted to mention there are two kinds of ajax request:
>>
>> - Requests that update a single component with no children.
>> - Requests that update an specified region in the page (for example
>> render="@form").
>>
>> I think in the first case, just include UIComponent.encodeAjax(...) is
>> more than enough. It is a good idea to send JSON instead xml to make
>> it less verbose.
>>
>> The second case is a bit hard to get it out. The most difficult case
>> is what happen with facelet dynamic tags and programmatically added
>> components (c:if, c:forEach, c:choose, ui:include src="#{...}",
>> ui:decorate template="#{...}"). For example:
>>
>> <h:panelGroup id="panelToUpdate">
>> <h:inputText value="#{myBean.input"/>
>> <c:if test=#{...}>
>> <h:outputText value="#{myBean.value"}/>
>> </c:if>
>> </h:panelGroup>
>>
>> I think a solution to the problem is just put a mark on the parent
>> component that holds the dynamic section, so the algorithm can be
>> aware that the content of the component is dynamically generated and
>> should be updated fully. We have already done things like that in
>> MyFaces 2.0
>> (org.apache.myfaces.REFRESH_TRANSIENT_BUILD_ON_PSS_PRESERVE_STATE
>> mode uses this as a way to identify which sections need to be saved
>> fully). Programmatically added components contains special markers
>> that are implementation specific. So, it could be good to add
>> UIComponent.markRenderDynamic(), UIComponent.isRenderDynamic()
>>
>> In few words, a good algorithm should be able to:
>>
>> - Identify when a component renders a "dynamic markup" and doesn't
>> have an associated id to the dom tree, or
>> - Identify if it contains some facelets dynamic components or
>> programmatically added components.
>>
>> One good use case where this feature could be helpful is <f:ajax
>> render="@form"/>. Instead send the whole form markup, the algorithm
>> will select recursively what really needs to be updated, saving render
>> time and bandwidth.
>>
>> KM>> I think there should also be a rendering hook for the
>> KM>> component in JavaScript so it can decide how to
>> KM>> render itself
>>
>> It has sense, if you can send something else on the response that is
>> not html markup, the component should be able to process it on the
>> client, and JSF should be able to help fill the gap. It is in fact a
>> mini-lifecycle:
>>
>> - Send request.
>> - Receive response.
>> - Decode response.
>> - Update DOM tree
>> - Update ViewState
>> - Invoke component handler passing the response (JSON or whatever).
>>
>> I have always thought jsf.ajax.request(...) onevent is very rigid,
>> because you can't post-process the incoming response (js function
>> callback).
>>
>> regards,
>>
>> Leonardo Uribe
>>
>> 2015-04-15 17:07 GMT-05:00 Leonardo Uribe <leonardo.uribe_at_irian.at>:
>> > Hi Kito
>> >
>> > KM>> I'm not 100% convinced your solution solves the focusing issue,
>> > though. How would it handle the following panel:
>> >
>> > Please note I'm trying not to mix this with the "focus" problem. We
>> > need a solution for that problem anyway, because the algorithm
>> > proposed here will not solve the main issue (sometimes there is no
>> > other choice than a full update).
>> >
>> > In that case the panel should be updated fully, because there is no
>> > "counterpart" in the DOM tree for the embedded html markup.
>> >
>> > Let's suppose that we have included UIComponent.encodeAjax(...) (and
>> > probably Renderer.encodeAjax(...)). The general algorithm should be
>> > something like this:
>> >
>> > - Call UIComponent.isRenderStatelessMarkup() for the panel.
>> > - If is false, do a full update as usual.
>> > - If is true, check on each child for isRenderStatelessMarkup().
>> > - For each "direct" children that does not return stateless
>> > markup, check UIComponent.isIdRenderedOnMarkup(). If every child that
>> > does not render stateless markup has an id rendered, invoke
>> > UIComponent.encodeAjax(...) on each child (even if is stateless
>> > markup). The result is the union of those invocations is equivalent to
>> > a full update.
>> > - Otherwise update fully.
>> >
>> > In the panel case, the UILeaf instance holding the EL expression
>> > #{myBean.value} will return isRenderStatelessMarkup() false and
>> > isIdRenderedOnMarkup() false, so the panel will be updated fully.
>> >
>> > The nice thing is if the component is something complex like a
>> > datatable, you can override encodeAjax(...) to do the logic in the
>> > same way the renderer does.
>> >
>> > The key point is that with the inclusion of
>> > UIComponent.encodeAjax(...), we gain more flexibility in the way how
>> > the view is updated after an ajax operation. I'm proposing here to do
>> > that and go further, adding a logic that could allow to check which
>> > pieces of information really needs to be updated.
>> >
>> > I have not checked each detail of the algorithm, but I have the
>> > feeling this is going to work. My only concern is the time spent
>> > iterating the component tree, so we need to adapt the algorithm to
>> > ensure linear complexity (maybe a two-step algorithm seems better).
>> >
>> > regards,
>> >
>> > Leonardo Uribe
>> >
>> > 2015-04-15 9:35 GMT-05:00 Kito Mann <kito.mann_at_virtua.com>:
>> >> Hello Leonardo,
>> >>
>> >> Thanks for the detailed explanation; I like what you're proposing for
>> >> partial updates; you have provided the implementation details of the
>> JSON
>> >> rendering feature I mentioned at JavaOne, except without JSON, of
>> course
>> >> (which is fine). In addition, I think there should also be a rendering
>> hook
>> >> for the component in JavaScript so it can decide how to render itself
>> (this
>> >> way, the component can decide the attributes refer to something other
>> than
>> >> specific DOM element attributes).
>> >>
>> >> I'm not 100% convinced your solution solves the focusing issue,
>> though. How
>> >> would it handle the following panel:
>> >>
>> >> <h:panelGroup id="panelToUpdate">
>> >> <h:inputText value="#{myBean.input"/>
>> >> <h:outputText value="#{myBean.value"}/>
>> >> #{myBean.value}
>> >> </h:panelGroup>
>> >>
>> >>
>> >> ___
>> >>
>> >> Kito D. Mann | @kito99 | Author, JSF in Action
>> >> Virtua, Inc. | http://www.virtua.com | JSF/Java EE training and
>> consulting
>> >> http://www.JSFCentral.com | @jsfcentral
>> >> +1 203-998-0403
>> >>
>> >> * Listen to the Enterprise Java Newscast:
>> http://enterprisejavanews.com
>> >> * JSFCentral Interviews Podcast:
>> >> http://www.jsfcentral.com/resources/jsfcentralpodcasts/
>> >> * Sign up for the JSFCentral Newsletter:
>> http://oi.vresp.com/?fid=ac048d0e17
>> >>
>> >> On Tue, Apr 14, 2015 at 9:42 PM, Leonardo Uribe <
>> leonardo.uribe_at_irian.at>
>> >> wrote:
>> >>>
>> >>> Hi
>> >>>
>> >>> I would like to point out some details on the JSF spec about how the
>> ajax
>> >>> update is being done. This is related to the topic "Handling Focus on
>> >>> Ajax".
>> >>> My intention is answer the question "why JSF update the whole markup
>> and
>> >>> not only the affected attributes" and identify the current flaws on
>> the
>> >>> spec.
>> >>>
>> >>> In my opinion this is a REALLY IMPORTANT FIX, and fortunately the
>> solution
>> >>> can
>> >>> be done with a bit of effort.
>> >>>
>> >>> The problem is all about how a JSF Component is rendered using an ajax
>> >>> request.
>> >>> According to JSF 2.2 spec section 13.4.3 Partial View Rendering, it
>> >>> says something
>> >>> like this:
>> >>>
>> >>> "... The UIViewRoot getRendersChildren and encodeChildren methods must
>> >>> determine
>> >>> if the request is an Ajax request using the
>> FacesContext.isAjaxRequest()
>> >>> method.
>> >>> If PartialViewContext.isAjaxRequest() returns true, then the
>> >>> getRendersChildren
>> >>> method must return true and the encodeChildren method must perform
>> partial
>> >>> rendering using the PartialViewContext.processPartial implementation
>> ..."
>> >>>
>> >>> This is what it says on PartialViewContext.processPartial(...)
>> javadoc:
>> >>>
>> >>> "... Perform lifecycle processing on components during the indicated
>> >>> phaseId.
>> >>> Only those components with identifiers existing in the Collection
>> returned
>> >>> from
>> >>> getExecuteIds() and getRenderIds() will be processed. ..."
>> >>>
>> >>> In few words, PartialViewContext.processPartial(RENDER_RESPONSE_PHASE)
>> >>> method
>> >>> is the one responsible of call encodeXXX methods.
>> >>>
>> >>> The problem can be seen when you take a look at how the default
>> algorithm
>> >>> for
>> >>> PartialViewContext.processPartial(...) really works. I'll describe the
>> >>> steps
>> >>> done by this algorithm by default in MyFaces (only what's relevant of
>> >>> course):
>> >>>
>> >>> - Get PartialResponseWriter
>> >>> - Call writer.startDocument() and set id attribute
>> >>> - If isRenderAll() true then
>> >>> - Call writer.startUpdate()
>> >>> - Call component.encodeAll() for every children of UIViewRoot
>> instance
>> >>> - Call writer.endUpdate()
>> >>> - Otherwise for each component in renderIds:
>> >>> - Call writer.startUpdate()
>> >>> - Call component.encodeAll()
>> >>> - Call writer.endUpdate()
>> >>> - Call writer.endDocument()
>> >>>
>> >>> Now, let's suppose you have a component and you know that the only
>> thing
>> >>> that
>> >>> changes between ajax request is the attributes attached with
>> >>> ValueExpression
>> >>> instances. In
>> >>>
>> >>> <h:inputText value="#{myBean.value}">
>> >>> <f:ajax ...>
>> >>> </h:inputText>
>> >>>
>> >>> HTML Markup
>> >>>
>> >>> <input id="j_id_23" type="text" value="..."/>
>> >>>
>> >>> Only changes "value" attribute, right?.
>> >>>
>> >>> How to do it with the current plumbing? If you take a look at the xsd
>> of
>> >>> web-partialresponse, you can see this is a possible response:
>> >>>
>> >>> <partial-response id="j_id_0">
>> >>> <changes>
>> >>> <attributes id="j_id_23">
>> >>> <attribute name="value" value="new value">
>> >>> </attributes>
>> >>> <update id="otherCompId"><![CDATA[... HTML Markup
>> ...]]></update>
>> >>> </changes>
>> >>> </partial-response>
>> >>>
>> >>> The problem is the default algorithm is not flexible enough, because
>> the
>> >>> component cannot choose the proper command. By default, a call to
>> update
>> >>> the DOM markup is always done and it is always called encodeAll().
>> >>>
>> >>> Third-Party vendors usually override
>> >>> PartialViewContext.processPartial(...)
>> >>> to do some extra processing, but on the way, they override existing
>> >>> behavior
>> >>> and create incompatibilities between libraries overriding the same
>> lines
>> >>> of
>> >>> code.
>> >>>
>> >>> The proposal is add a new method in UIComponent called
>> >>> encodeAjax(FacesContext context, PartialResponseWriter writer) that by
>> >>> default execute something like this:
>> >>>
>> >>> try
>> >>> {
>> >>> writer.startUpdate();
>> >>> this.encodeAll();
>> >>> } finally {
>> >>> writer.endUpdate();
>> >>> }
>> >>>
>> >>> In other words, move the code that writes the "update" section to the
>> >>> component,
>> >>> to let the component choose how and when should be updated. In that
>> way,
>> >>> the component can choose between the valid options:
>> >>>
>> >>> - update
>> >>> - insert DOM node
>> >>> - delete
>> >>> - attributes
>> >>> - eval
>> >>> - extension
>> >>>
>> >>> This change will provide a lot of flexibility that currently we just
>> don't
>> >>> have
>> >>> "out of the box".
>> >>>
>> >>> Let's try something more complex. Suppose this code:
>> >>>
>> >>> <div id="myBigAndComplexPanel">
>> >>> <!-- A big stateless chunk of HTML Markup -->
>> >>> <input id="j_id_23" type="text" value="..."/>
>> >>> <!-- Another big fat stateless chunk of HTML Markup -->
>> >>> </div>
>> >>>
>> >>> And I want to update "myBigAndComplexPanel", but I know that the only
>> >>> thing I
>> >>> really need is update the input value. How?
>> >>>
>> >>> The key point is to know if each component that matters has an id
>> rendered
>> >>> on
>> >>> the DOM markup. If the id is not rendered, we can't update the
>> component
>> >>> individually, because we don't have the reference, and we will be
>> forced
>> >>> to
>> >>> update the whole DOM markup for the panel. Suppose the triggering ajax
>> >>> says this:
>> >>>
>> >>> <f:ajax ... render="myBigAndComplexPanel"/>
>> >>>
>> >>> The algorithm call UIComponent.encodeAjax(...) for the panel. Inside,
>> the
>> >>> component can check if is "stateless" or not, and then invoke
>> >>> UIComponent.encodeAjax for each child component. UILeaf instances
>> (HTML
>> >>> markup)
>> >>> will not process anything, unless they contain embedded EL, but the
>> input
>> >>> component will think the best way to update itself and at the end it
>> will
>> >>> add the <attributes>...</attributes> block. If we can identify when
>> the
>> >>> output of a component has an id (UIComponent.isIdRenderedOnMarkup())
>> or
>> >>> contains static markup or not (UIComponent.isRenderStatelessMarkup()),
>> >>> this
>> >>> strategy will work. Also something like
>> UIComponent.getUpdatedAttributes()
>> >>> that used the "delta" state or the existence of ValueExpression
>> instances
>> >>> in
>> >>> attributes, to get which ones were changes and build the response.
>> >>>
>> >>> In summary: "why JSF update the whole markup and not only the affected
>> >>> attributes". Because "<update>" solves most of the use cases in core
>> JSF.
>> >>> It can be done, but there are some use cases that are not so simple
>> to do
>> >>> and requires some work. Anyway the fix for "handling focus" is
>> required.
>> >>>
>> >>> regards,
>> >>>
>> >>> Leonardo Uribe
>> >>
>> >>
>>
>
>