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

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

From: Kito Mann <kito.mann_at_virtua.com>
Date: Tue, 6 Sep 2016 09:54:46 -0400

Is there a spec issue for this?

___

Kito D. Mann | @kito99 | Author, JSF in Action
Web Components, Polymer, JSF, PrimeFaces, Java EE, and Liferay training and
consulting
Virtua, Inc. | virtua.tech
JSFCentral.com | @jsfcentral | knowesis.io
<http://knowesis.io/web/webcomponents> - fresh Web Components info
+1 203-998-0403

* Listen to the Enterprise Java Newscast: *http://
<http://blogs.jsfcentral.com/JSFNewscast/>enterprisejavanews.com
<http://ww.enterprisejavanews.com>*


On Wed, Jun 22, 2016 at 9:07 AM, Leonardo Uribe <leonardo.uribe_at_irian.at>
wrote:

> 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-babbageface
>> s-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.processPart
>>> ial(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.isRenderStateless
>>> Markup()),
>>> >>> 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
>>> >>
>>> >>
>>>
>>
>>
>