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

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: [JAVASERVERFACES_SPEC_PUBLIC-1404] Add UIViewRoot#getRenderedComponentResources()

From: Neil Griffin <neil.griffin_at_portletfaces.org>
Date: Fri, 1 Jul 2016 13:59:13 -0400

FYI, my colleague Kyle Stiemann will be commenting on the following issue in JIRA:
https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1404

Please click on the "watch" link in JIRA if you are interested. Thanks.

> On Jun 25, 2016, at 4:49 AM, Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:
>
> Hi
>
> I agree it is necessary to do something on the client and something on the server.
>
> In the client, it should be some algorithm that checks if the resource has been already loaded and if that so do not do it again (well, it is not really necessary, because at the end the browser already take care of that).
>
> On the server we don't really need the full list of all rendered resources. You can make two groups of resources:
>
> 1. Resources with target="...." (h:outputStylesheet is by default)
> 2. Resources without target (rendered inline).
>
> In an ajax request, if the resource does not have a target set (group 2), it will be rendered inline anyway as part of the update component payload. It could be situations where the resource has been already loaded, but we can't really detect this case without keep track on of the list on the state. But I would like to point out that this case is not very often, because most of the times, the resources are rendered with target, and that ALWAYS leaves a trace on the component tree (as a underlying UIOutput instance with a renderer for h:outputScript or h:outputStylesheet).
>
> But I have realised that it is possible to do the algorithm to build the resource list on ajax request using a custom event as an implementation detail (since h:outputScript and h:outputStylesheet are unique components not rewritten by third party libraries or there are no third party components similar to them that does not extend from them).
>
> I don't really care about the implementation you do on the RI side, but what I care is the documentation/javadoc of this part should be enough to allow the algorithm I'm proposing here to work.
>
> BS>> Storing it in the view state is the only server side way.
> BS>> Relying on a rebuilt view is insufficient as it doesn't
> BS>> reveal which components and associated resources
> BS>> have been conditionally rendered/toggled during all
> BS>> previous postbacks. Whether that's "cheap" is a second.
>
> As I said before, and to clarify my personal opinion, the cost of store this list on the state is something we should really avoid, and we don't need the perfect solution, just one good enough to fulfil the real need. I understand the case related to components conditionally rendered/toggled, but what really matters is if the resource was added to the ajax request, not if at some point we forgot to add it again.
>
> What I'm just trying is to find a good balance between the requirements and some performance issues I can see in this case. I'll be happy if the spec javadoc is good enough to say what this list is all about but allow different algorithm implementations. It doesn't have to mention any implementation details. I understand the views from Mojarra team could be different. Please note the only intention here is share my thoughts as a contributor to MyFaces project.
>
> regards,
>
> Leonardo Uribe
>
>
> 2016-06-24 10:26 GMT+02:00 Bauke Scholtz <balusc_at_gmail.com>:
> Storing it in the view state is the only server side way. Relying on a rebuilt view is insufficient as it doesn't reveal which components and associated resources have been conditionally rendered/toggled during all previous postbacks. Whether that's "cheap" is a second.
>
> Cheers, B
>
>
> On Fri, Jun 24, 2016 at 9:19 AM, Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:
> But that means the resource path could be sent over and over per each ajax request. If there is a cheap way to check it from the server without a network overhead we should take it.
>
> If we fix the dynamic resource loading without fix this we will fall in this situation.
>
> On Jun 23, 2016 7:05 PM, "Bauke Scholtz" <balusc_at_gmail.com> wrote:
> Another way would be passing resource path to JS and have it check if it's already in DOM and if not, then dynamically create script element.
>
> Cheers, B
>
>
> On Thu, Jun 23, 2016, 16:20 Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:
> Hi
>
> I have seen this issue opened:
>
> https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1404
> Add UIViewRoot#getRenderedComponentResources()
>
> I would like to contribute with some thoughts about this issue that could help to solve
> some issues we already have in this part, and that could be fixed on the way.
>
> In MyFaces as you already know there is also a map that is used to indicate when
> a resource has been already rendered in the response.
>
> This solution is far from being perfect. It just check if a resource has been rendered
> more that once on the current request but:
>
> - On each request this map is filled over and over and over again. By performance
> reasons, this map is not saved on the state, but in fact each resource has one or
> many associated components that just point to each resource, so this information is
> in the tree structure, but there is no standard way to calculate it from the current
> view.
>
> - If you are building the whole view, you want this map to be empty before render the
> view, but on an ajax request things change, because in this case you assume there is
> already a view built on the client with the scripts, so you want this map already filled
> but before render the ajax fragment.
>
> If we remember the case "Dynamic resource loading in ajax requests", if we don't solve
> this problem some scripts could be loaded over and over even if they have been already
> there by other components.
>
> So, this is a "transient" HashSet that should be cleared and filled when the view is fully
> built. But in an ajax request, we need something to rebuild the set before render the ajax
> fragments. We don't need to traverse the whole tree, because we know that all resource
> components that matters can be retrieved from UIViewRoot.getComponentResources(...)
> (look with target=head, body or form).
>
> I can imagine a custom component event to register the resources on the map and a
> @ListenerFor annotation of each renderer (h:outputScript and h:outputStylesheet). It is not
> necessary to traverse the whole component tree, just a small fragment of the tree, and
> it is necessary to give each component a way to register themselves on the map. Again,
> this requires some changes on the spec. The reason why the components must register
> themselves is there are the case where h:outputScript renders as a script block so the
> algorithm should skip those components and the only way to know that is ask to each
> component itself.
>
> regards,
>
> Leonardo Uribe
>
>