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

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

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Mon, 24 Oct 2016 23:16:24 -0500

Hi

Sorry for the late response. This issue has been mentioned before in:

https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-620
Allow components to emit ajax xml

https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-674
Allow ajax response short-circuit/override

https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-785
Ajax rendering lifecycle for components half broken + Solution.

All of them complain about the same: There is no way to customize the ajax
payload from a component oriented perspective, so the developer is
restricted to use <update> only.

regards,

Leonardo Uribe


2016-09-06 8:54 GMT-05:00 Kito Mann <kito.mann_at_virtua.com>:

> 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_TR
>>>> ANSIENT_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
>>>> >>
>>>> >>
>>>>
>>>
>>>
>>
>