[JAVASERVERFACES_SPEC_PUBLIC-770] add component resources depending on the owner component state Created: 17/Mar/10  Updated: 12/Aug/14

Status: Open
Project: javaserverfaces-spec-public
Component/s: Components/Renderers
Affects Version/s: 2.0
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: lu4242 Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Operating System: All
Platform: All

Issuezilla Id: 770
Status Whiteboard:

size_large importance_small


All this text is extracted from jsr-314-open mailing list and it is put here as

[jsr-314-open] add component resources depending on the owner component state

Trying to use the new JSF 2.0 Resource Api I have found one case that maybe it
is of interest on this list.

Suppose a component that needs to add some specific javascript/css file based on
a value. In tomahawk we can do it something like this on the renderer:

if( tabbedPane.isClientSide() ){
AddResource.HEADER_BEGIN, HtmlTabbedPaneRenderer.class, "dynamicTabs.js");

This code works because the response is buffered and post-processed.

The problem is how to do that with JSF 2.0?

One could think on use a listener attached to PreRenderComponentEvent, but this
event is called before encodeBegin, so it is useless in this case, because we
need to call it before the whole view is rendered.

Then, you can think do something like this:

@ListenerFor(systemEventClass = PreRenderViewEvent.class)
public class HtmlTabbedPaneRenderer extends HtmlRenderer

It does not work too. The reason is the listener is attached to the component
instance, and only the UIViewRoot instance receives the event. If we do the same
as f:event does when PreRenderViewEvent is found (suscribe the listener on
UIViewRoot) we lose the component we are referencing, because it is replaced by

I can solve this one creating a wrapper for ViewHandler that publish a custom
event for all components before render view. but the big question is if jsf 2.0
should support this use case out of the box.

>> Cagatay Civici
>> Why not listening to PostAddToViewEvent with;
>> @ListenerFor(systemEventClass = PostAddToViewEvent.class)
>>public class HtmlTabbedPane extends UIComponentBase

{ >>}

>> and in event listener;
>> if(this.isClientSide()) {
>> viewroot.addComponentResource(...);

Does not work too because in a postback, PostAddToViewEvent occur in the
following cases:

  • With Partial State Saving enabled when the view is build but before the state
    of the component is restored.
  • With Partial State Saving disabled when the view is "refreshed", because all
    component nodes are detached and attached to the tree.

Now suppose the component has a ValueExpression attached to the property, and
the value changes on Invoke Application Phase. With partial state saving the
tree was already build, so it doesn't catch the logic. With partial state saving
disabled, the event occur twice, the first time when the tree structure is
build, the second time when the view is updated, so again it doesn't work,
because if the resource component (it is transient too) was already added, it
cannot be removed later.

>> Ed Burns
>>Please correct me if I'm wrong, but the problem you state above seems to
>>be just another example of the garden variety "conditional value changes
>>between requests or during a request".

Yes and no. The difference with other examples of the garden is to add a
component resource, we need to do it in the right time, since it requires to
update the component tree adding components before render it, but after we know
which view will be rendered. Please note by a previous fix, all component
resources are transient.

As a side note, if someone wants to do this in a composite component he/she
probable do this:

<c:if test="#


<h:outputStylesheet ..../>

And it works in myfaces because we have a fix for the c:if problem.

>> Do we need PreAddComponentResourceEvent and
>> PostAddComponentResourceEvent?

In my opinion is only necessary to add only one event. The right place is after
resolve PreRenderViewEvent, because only in that time we know the current
component tree is the view that will be rendered.

It is not possible to use PreRenderComponentEvent because it is called on
encodeBegin and the view header was already rendered.

It is not possible to use PreRenderViewEvent like this:

@ListenerFor(systemEventClass = PreRenderViewEvent.class)
public class HtmlTabbedPaneRenderer extends HtmlRenderer

because the listener is attached to the component when it is created, but the
event is only received by the current UIViewRoot. If we fix the algorithm on
Application class to attach this listener to the current UIViewRoot instance,
the source of the event will be UIViewRoot, and traverse the tree to find the
component is worse. Note other option is publish PreRenderViewEvent for all
child components, but after know the view that will be rendered.

In conclusion, for make this use case possible we need two things:

1. The right time to add the resource to the component tree.
2. The component with its state restored and updated.

Thinking more about it, another option about put this code could be on
vld.buildView method, but note when partial state saving is enabled this method
return immediately (maybe it is possible to change it).

Comment by Ed Burns [ 18/May/10 ]

Move to 2.1

Comment by Ed Burns [ 08/Jun/10 ]


Comment by Ed Burns [ 22/Jun/10 ]


Comment by rogerk [ 27/Oct/10 ]


Comment by rogerk [ 16/Nov/10 ]


Comment by Ed Burns [ 01/Aug/14 ]

Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.

Generated at Wed Apr 01 10:36:52 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.