users@javaserverfaces-spec-public.java.net

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

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Thu, 23 Jun 2016 16:19:29 +0200

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