You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Wesley Hales <we...@gmail.com> on 2007/05/08 20:36:09 UTC

Multiple calls on isRendered - Performance issue

Hello - Why do we continually call isRendered after encodeBegin()? Once the
begin tag is written out, it shouldn't matter what the body and end rendered
states are.

Facelets 1.1.11
Myfaces 1.1.5 & 1.2

So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
The #{MyBean.alerts method is called 5 times! and it is like this for every
EL eval on the page. I do know that EL can only bind to the FaceletsContext
and no other scopes... So are there any other options than what I have
listed below?

1. Tried to modify MyFaces src in UIComponentBase:
public boolean isRendered()
     {
           if(_rendered == null){

           // our modification! Only compute the rendered value once, and
cache for the rest of the lifecycle.
           Boolean rend = getExpressionValue("rendered", _rendered,
DEFAULT_RENDERED);
           _rendered = rend.booleanValue();
           }
         return _rendered;
     }
This didn't work :( - Something happend to A4J and we had no ideas what the
implication would be on all components.

2. Tried using Facelets <ui:param and <c:set to store the EL in a page
scoped variable, then have the variable evaluated in the rendered attribute.
This didn't work either because it is on FacesContext.

So this may just be me not fully understanding  what JSF does behind the
scenes of component rendering, or some people say that  the spec is screwed
up when it comes to this. I'm sure some of the pros can help me out here :).

Thx,
Wesley Hales

Re: How to effectively control the table cell width

Posted by Alexander Wallace <aw...@rwmotloc.com>.
can't you use columnClasses for it?

On May 12, 2007, at 9:53 PM, iSquareOne LLC wrote:

> Hey, all,
> Maybe I am missing something. I can't find a way to effectively  
> control the table cell width. In my code, I use panelGrid to  
> display a table, but I don't see a way to specify the width for  
> each column (or the width of the table cell). I do see there is a  
> way to use t:dataTable and t:column to make this happen, but  
> dataTable is too heavy for my purpose unless this is the only  
> option. So can you please shed some light on this? Thanks in advance!
>
> - SL
>
> Ready for the edge of your seat? Check out tonight's top picks on  
> Yahoo! TV.


How to effectively control the table cell width

Posted by iSquareOne LLC <is...@yahoo.com>.
Hey, all,
Maybe I am missing something. I can't find a way to effectively control the table cell width. In my code, I use panelGrid to display a table, but I don't see a way to specify the width for each column (or the width of the table cell). I do see there is a way to use t:dataTable and t:column to make this happen, but dataTable is too heavy for my purpose unless this is the only option. So can you please shed some light on this? Thanks in advance!

- SL

       
---------------------------------
Ready for the edge of your seat? Check out tonight's top picks on Yahoo! TV. 

Re: Multiple calls on isRendered - Performance issue

Posted by Wesley Hales <we...@gmail.com>.
 Do you think it's a good idea to have method calls to a API or DAO in the
getter methods? I really havent seen that before in any other apps, but
maybe it is a best practice that I haven't seen yet. Or maybe we just didn't
understand the impact it would have in the lifecycle of JSF in our early,
unexperienced JSF development.
So, what if we keep the getters/members of the class as is... give them a
setter to conform to javabean spec and set/populate all of them in a) the
constructor or b) in some kind of setup method for that backing bean? That
way they can be called as many times as the framework wants, but only one
service call is made in the inital setup of the bean.

This way, the framework can brutally call whatever it wants and we won't
always be trying to prevent some kind of new behavior/enhancement.

This isn't trying to excuse the isRendered calls, but if the architecture of
the backingBean is that important, then I consider this very important info
for a high traffic, highly visible application.

Wes

On 5/10/07, Adam Winer <aw...@gmail.com> wrote:
>
> On 5/10/07, Wesley Hales <we...@gmail.com> wrote:
> > Yeah, we tried Adam's proposal before I posted the patch... It worked up
> > until Ajax4JSF usage and components like UIColumn were not updating.
>
> I'd like to know why that's so - Ajax4JSF must be
> doing something at least a little unusual for this
> to break.
>
> -- Adam
>
>
> >
> > So, after using the patch and making changes to not extend
> > UIComponentBaseCached in UIColumn and UIGraphic *we had problems with
> items
> > in datatable not updating* - Everything seems to be working fine.
> >
> > Again, I know this is not an elegant solution, especially when you have
> to
> > pick and choose which base components are using the isRendered cache.
> >
> > Thanks again for looking into this Adam, Simon, Andrew.
> > Regards,
> > Wesley
> >
> >
> > On 5/10/07, Simon Kitching <si...@rhe.co.nz> wrote:
> > > Thanks Adam. That makes good sense.
> > >
> > > All that is needed now is a volunteer to implement it :-).
> > >
> > > I might have a go if I can find some spare time but it won't be soon.
> I
> > > will try to find time to record this as an enhancement in JIRA so it
> > > doesn't get lost.
> > >
> > > Regards,
> > >
> > > Simon
> > >
> > > Adam Winer wrote:
> > > > Technically, rendered is supposed to be:
> > > > - Constant across
> > encodeBegin()/encodeChildren()/encodeEnd()
> > > > - Constant across processDecodes()/processValidators()/
> > > >   processUpdateModel().
> > > >
> > > > Unfortunately, the latter doesn't help - since a component inside
> > > > a table would have processDecodes() called repeatedly,
> > > > then processValidators() repeatedly, etc. - and "rendered"
> > > > could be different from one row to the next.
> > > >
> > > > But the former should be fine - if you always fetch and
> > > > store the value in encodeBegin() (whether or not encodeBegin()
> > > > has previously been called), then use that in encodeChildren()
> > > > and encodeEnd(), you should be fine.
> > > >
> > > > -- Adam
> > > >
> > > >
> > > > On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
> > > >> Andrew, are you just stating what currently happens or are you
> saying
> > > >> that there is a *reason* for evaluating "rendered" in encodeBegin,
> > > >> encodeChildren and encodeEnd?
> > > >>
> > > >> I can't initially see any reason why it would need to be evaluated
> more
> > > >> than once.
> > > >>
> > > >> UIComponentBase does indeed call isRendered in encodeBegin,
> > > >> encodeChildren and encodeEnd. It also implements isRendered as an
> > > >> evaluation of the EL expression (myfaces 1.1.3 implementation).
> > > >>
> > > >> But As Wesley asks, why would it ever make sense for rendered to be
> > true
> > > >> in encodeBegin, but false in encodeEnd? I cannot see any way that
> would
> > > >> be useful, so why not just compute it once then cache it somewhere
> for
> > > >> the rest of that render cycle (eg in a "transient" member of the
> > > >> component)? This would be a significant performance boost..
> > > >>
> > > >> Wesley, your proposed modification which stores the rendered state
> into
> > > >> _rendered is not good because setting _rendered will permanently
> > > >> override the rendered EL expression, not just for the current
> render
> > > >> cycle but for the lifetime of that component. What is needed is to
> > > >> figure out when the first call to isRendered is done *during the
> render
> > > >> cycle* and then cache that until rendering finishes. Note that
> > > >> isRendered is also called during postback processing, and it's
> > perfectly
> > > >> reasonable to change this value between postback and render so
> caching
> > > >> really should only be done between encodeBegin() and encodeEnd().
> So
> > > >> implementing this optimisation is a little tricky - but not
> impossible
> > > >> I'm sure.
> > > >>
> > > >> Regards,
> > > >>
> > > >> Simon
> > > >>
> > > >> Andrew Robinson wrote:
> > > >> > At the very least rendered is called during encodeBegin,
> > > >> > encodeChildren, and encodeEnd.
> > > >> >
> > > >> > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> > > >> >> Hello - Why do we continually call isRendered after
> encodeBegin()?
> > > >> >> Once the
> > > >> >> begin tag is written out, it shouldn't matter what the body and
> end
> > > >> >> rendered
> > > >> >> states are.
> > > >> >>
> > > >> >> Facelets 1.1.11
> > > >> >>  Myfaces 1.1.5 & 1.2
> > > >> >>
> > > >> >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> > > >> >> The #{MyBean.alerts method is called 5 times! and it is like
> this
> > for
> > > >> >> every
> > > >> >> EL eval on the page. I do know that EL can only bind to the
> > > >> >> FaceletsContext
> > > >> >> and no other scopes... So are there any other options than what
> I
> > have
> > > >> >> listed below?
> > > >> >>
> > > >> >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > >> >> public boolean isRendered()
> > > >> >>      {
> > > >> >>            if(_rendered == null){
> > > >> >>
> > > >> >>            // our modification! Only compute the rendered value
> > > >> once, and
> > > >> >> cache for the rest of the lifecycle.
> > > >> >>            Boolean rend = getExpressionValue("rendered",
> _rendered,
> > > >> >> DEFAULT_RENDERED);
> > > >> >>            _rendered = rend.booleanValue();
> > > >> >>            }
> > > >> >>          return _rendered;
> > > >> >>      }
> > > >> >> This didn't work :( - Something happend to A4J and we had no
> ideas
> > > >> >> what the
> > > >> >> implication would be on all components.
> > > >> >>
> > > >> >> 2. Tried using Facelets <ui:param and <c:set to store the EL in
> a
> > page
> > > >> >> scoped variable, then have the variable evaluated in the
> rendered
> > > >> >> attribute.
> > > >> >> This didn't work either because it is on FacesContext.
> > > >> >>
> > > >> >> So this may just be me not fully understanding  what JSF does
> > > >> behind the
> > > >> >> scenes of component rendering, or some people say that  the spec
> is
> > > >> >> screwed
> > > >> >> up when it comes to this. I'm sure some of the pros can help me
> out
> > > >> >> here :).
> > > >> >>
> > > >> >> Thx,
> > > >> >> Wesley Hales
> > > >>
> > > >>
> > >
> > >
> >
> >
>

Re: Multiple calls on isRendered - Performance issue

Posted by Adam Winer <aw...@gmail.com>.
On 5/10/07, Wesley Hales <we...@gmail.com> wrote:
> Yeah, we tried Adam's proposal before I posted the patch... It worked up
> until Ajax4JSF usage and components like UIColumn were not updating.

I'd like to know why that's so - Ajax4JSF must be
doing something at least a little unusual for this
to break.

-- Adam


>
> So, after using the patch and making changes to not extend
> UIComponentBaseCached in UIColumn and UIGraphic *we had problems with items
> in datatable not updating* - Everything seems to be working fine.
>
> Again, I know this is not an elegant solution, especially when you have to
> pick and choose which base components are using the isRendered cache.
>
> Thanks again for looking into this Adam, Simon, Andrew.
> Regards,
> Wesley
>
>
> On 5/10/07, Simon Kitching <si...@rhe.co.nz> wrote:
> > Thanks Adam. That makes good sense.
> >
> > All that is needed now is a volunteer to implement it :-).
> >
> > I might have a go if I can find some spare time but it won't be soon. I
> > will try to find time to record this as an enhancement in JIRA so it
> > doesn't get lost.
> >
> > Regards,
> >
> > Simon
> >
> > Adam Winer wrote:
> > > Technically, rendered is supposed to be:
> > > - Constant across
> encodeBegin()/encodeChildren()/encodeEnd()
> > > - Constant across processDecodes()/processValidators()/
> > >   processUpdateModel().
> > >
> > > Unfortunately, the latter doesn't help - since a component inside
> > > a table would have processDecodes() called repeatedly,
> > > then processValidators() repeatedly, etc. - and "rendered"
> > > could be different from one row to the next.
> > >
> > > But the former should be fine - if you always fetch and
> > > store the value in encodeBegin() (whether or not encodeBegin()
> > > has previously been called), then use that in encodeChildren()
> > > and encodeEnd(), you should be fine.
> > >
> > > -- Adam
> > >
> > >
> > > On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
> > >> Andrew, are you just stating what currently happens or are you saying
> > >> that there is a *reason* for evaluating "rendered" in encodeBegin,
> > >> encodeChildren and encodeEnd?
> > >>
> > >> I can't initially see any reason why it would need to be evaluated more
> > >> than once.
> > >>
> > >> UIComponentBase does indeed call isRendered in encodeBegin,
> > >> encodeChildren and encodeEnd. It also implements isRendered as an
> > >> evaluation of the EL expression (myfaces 1.1.3 implementation).
> > >>
> > >> But As Wesley asks, why would it ever make sense for rendered to be
> true
> > >> in encodeBegin, but false in encodeEnd? I cannot see any way that would
> > >> be useful, so why not just compute it once then cache it somewhere for
> > >> the rest of that render cycle (eg in a "transient" member of the
> > >> component)? This would be a significant performance boost..
> > >>
> > >> Wesley, your proposed modification which stores the rendered state into
> > >> _rendered is not good because setting _rendered will permanently
> > >> override the rendered EL expression, not just for the current render
> > >> cycle but for the lifetime of that component. What is needed is to
> > >> figure out when the first call to isRendered is done *during the render
> > >> cycle* and then cache that until rendering finishes. Note that
> > >> isRendered is also called during postback processing, and it's
> perfectly
> > >> reasonable to change this value between postback and render so caching
> > >> really should only be done between encodeBegin() and encodeEnd(). So
> > >> implementing this optimisation is a little tricky - but not impossible
> > >> I'm sure.
> > >>
> > >> Regards,
> > >>
> > >> Simon
> > >>
> > >> Andrew Robinson wrote:
> > >> > At the very least rendered is called during encodeBegin,
> > >> > encodeChildren, and encodeEnd.
> > >> >
> > >> > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> > >> >> Hello - Why do we continually call isRendered after encodeBegin()?
> > >> >> Once the
> > >> >> begin tag is written out, it shouldn't matter what the body and end
> > >> >> rendered
> > >> >> states are.
> > >> >>
> > >> >> Facelets 1.1.11
> > >> >>  Myfaces 1.1.5 & 1.2
> > >> >>
> > >> >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> > >> >> The #{MyBean.alerts method is called 5 times! and it is like this
> for
> > >> >> every
> > >> >> EL eval on the page. I do know that EL can only bind to the
> > >> >> FaceletsContext
> > >> >> and no other scopes... So are there any other options than what I
> have
> > >> >> listed below?
> > >> >>
> > >> >> 1. Tried to modify MyFaces src in UIComponentBase:
> > >> >> public boolean isRendered()
> > >> >>      {
> > >> >>            if(_rendered == null){
> > >> >>
> > >> >>            // our modification! Only compute the rendered value
> > >> once, and
> > >> >> cache for the rest of the lifecycle.
> > >> >>            Boolean rend = getExpressionValue("rendered", _rendered,
> > >> >> DEFAULT_RENDERED);
> > >> >>            _rendered = rend.booleanValue();
> > >> >>            }
> > >> >>          return _rendered;
> > >> >>      }
> > >> >> This didn't work :( - Something happend to A4J and we had no ideas
> > >> >> what the
> > >> >> implication would be on all components.
> > >> >>
> > >> >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> page
> > >> >> scoped variable, then have the variable evaluated in the rendered
> > >> >> attribute.
> > >> >> This didn't work either because it is on FacesContext.
> > >> >>
> > >> >> So this may just be me not fully understanding  what JSF does
> > >> behind the
> > >> >> scenes of component rendering, or some people say that  the spec is
> > >> >> screwed
> > >> >> up when it comes to this. I'm sure some of the pros can help me out
> > >> >> here :).
> > >> >>
> > >> >> Thx,
> > >> >> Wesley Hales
> > >>
> > >>
> >
> >
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Wesley Hales <we...@gmail.com>.
Yeah, we tried Adam's proposal before I posted the patch... It worked up
until Ajax4JSF usage and components like UIColumn were not updating.

So, after using the patch and making changes to not extend
UIComponentBaseCached in UIColumn and UIGraphic *we had problems with items
in datatable not updating* - Everything seems to be working fine.

Again, I know this is not an elegant solution, especially when you have to
pick and choose which base components are using the isRendered cache.

Thanks again for looking into this Adam, Simon, Andrew.
Regards,
Wesley

On 5/10/07, Simon Kitching <si...@rhe.co.nz> wrote:
>
> Thanks Adam. That makes good sense.
>
> All that is needed now is a volunteer to implement it :-).
>
> I might have a go if I can find some spare time but it won't be soon. I
> will try to find time to record this as an enhancement in JIRA so it
> doesn't get lost.
>
> Regards,
>
> Simon
>
> Adam Winer wrote:
> > Technically, rendered is supposed to be:
> > - Constant across encodeBegin()/encodeChildren()/encodeEnd()
> > - Constant across processDecodes()/processValidators()/
> >   processUpdateModel().
> >
> > Unfortunately, the latter doesn't help - since a component inside
> > a table would have processDecodes() called repeatedly,
> > then processValidators() repeatedly, etc. - and "rendered"
> > could be different from one row to the next.
> >
> > But the former should be fine - if you always fetch and
> > store the value in encodeBegin() (whether or not encodeBegin()
> > has previously been called), then use that in encodeChildren()
> > and encodeEnd(), you should be fine.
> >
> > -- Adam
> >
> >
> > On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
> >> Andrew, are you just stating what currently happens or are you saying
> >> that there is a *reason* for evaluating "rendered" in encodeBegin,
> >> encodeChildren and encodeEnd?
> >>
> >> I can't initially see any reason why it would need to be evaluated more
> >> than once.
> >>
> >> UIComponentBase does indeed call isRendered in encodeBegin,
> >> encodeChildren and encodeEnd. It also implements isRendered as an
> >> evaluation of the EL expression (myfaces 1.1.3 implementation).
> >>
> >> But As Wesley asks, why would it ever make sense for rendered to be
> true
> >> in encodeBegin, but false in encodeEnd? I cannot see any way that would
> >> be useful, so why not just compute it once then cache it somewhere for
> >> the rest of that render cycle (eg in a "transient" member of the
> >> component)? This would be a significant performance boost..
> >>
> >> Wesley, your proposed modification which stores the rendered state into
> >> _rendered is not good because setting _rendered will permanently
> >> override the rendered EL expression, not just for the current render
> >> cycle but for the lifetime of that component. What is needed is to
> >> figure out when the first call to isRendered is done *during the render
> >> cycle* and then cache that until rendering finishes. Note that
> >> isRendered is also called during postback processing, and it's
> perfectly
> >> reasonable to change this value between postback and render so caching
> >> really should only be done between encodeBegin() and encodeEnd(). So
> >> implementing this optimisation is a little tricky - but not impossible
> >> I'm sure.
> >>
> >> Regards,
> >>
> >> Simon
> >>
> >> Andrew Robinson wrote:
> >> > At the very least rendered is called during encodeBegin,
> >> > encodeChildren, and encodeEnd.
> >> >
> >> > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> >> >> Hello - Why do we continually call isRendered after encodeBegin()?
> >> >> Once the
> >> >> begin tag is written out, it shouldn't matter what the body and end
> >> >> rendered
> >> >> states are.
> >> >>
> >> >> Facelets 1.1.11
> >> >>  Myfaces 1.1.5 & 1.2
> >> >>
> >> >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> >> >> The #{MyBean.alerts method is called 5 times! and it is like this
> for
> >> >> every
> >> >> EL eval on the page. I do know that EL can only bind to the
> >> >> FaceletsContext
> >> >> and no other scopes... So are there any other options than what I
> have
> >> >> listed below?
> >> >>
> >> >> 1. Tried to modify MyFaces src in UIComponentBase:
> >> >> public boolean isRendered()
> >> >>      {
> >> >>            if(_rendered == null){
> >> >>
> >> >>            // our modification! Only compute the rendered value
> >> once, and
> >> >> cache for the rest of the lifecycle.
> >> >>            Boolean rend = getExpressionValue("rendered", _rendered,
> >> >> DEFAULT_RENDERED);
> >> >>            _rendered = rend.booleanValue();
> >> >>            }
> >> >>          return _rendered;
> >> >>      }
> >> >> This didn't work :( - Something happend to A4J and we had no ideas
> >> >> what the
> >> >> implication would be on all components.
> >> >>
> >> >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> page
> >> >> scoped variable, then have the variable evaluated in the rendered
> >> >> attribute.
> >> >> This didn't work either because it is on FacesContext.
> >> >>
> >> >> So this may just be me not fully understanding  what JSF does
> >> behind the
> >> >> scenes of component rendering, or some people say that  the spec is
> >> >> screwed
> >> >> up when it comes to this. I'm sure some of the pros can help me out
> >> >> here :).
> >> >>
> >> >> Thx,
> >> >> Wesley Hales
> >>
> >>
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Simon Kitching <si...@rhe.co.nz>.
Thanks Adam. That makes good sense.

All that is needed now is a volunteer to implement it :-).

I might have a go if I can find some spare time but it won't be soon. I 
will try to find time to record this as an enhancement in JIRA so it 
doesn't get lost.

Regards,

Simon

Adam Winer wrote:
> Technically, rendered is supposed to be:
> - Constant across encodeBegin()/encodeChildren()/encodeEnd()
> - Constant across processDecodes()/processValidators()/
>   processUpdateModel().
> 
> Unfortunately, the latter doesn't help - since a component inside
> a table would have processDecodes() called repeatedly,
> then processValidators() repeatedly, etc. - and "rendered"
> could be different from one row to the next.
> 
> But the former should be fine - if you always fetch and
> store the value in encodeBegin() (whether or not encodeBegin()
> has previously been called), then use that in encodeChildren()
> and encodeEnd(), you should be fine.
> 
> -- Adam
> 
> 
> On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
>> Andrew, are you just stating what currently happens or are you saying
>> that there is a *reason* for evaluating "rendered" in encodeBegin,
>> encodeChildren and encodeEnd?
>>
>> I can't initially see any reason why it would need to be evaluated more
>> than once.
>>
>> UIComponentBase does indeed call isRendered in encodeBegin,
>> encodeChildren and encodeEnd. It also implements isRendered as an
>> evaluation of the EL expression (myfaces 1.1.3 implementation).
>>
>> But As Wesley asks, why would it ever make sense for rendered to be true
>> in encodeBegin, but false in encodeEnd? I cannot see any way that would
>> be useful, so why not just compute it once then cache it somewhere for
>> the rest of that render cycle (eg in a "transient" member of the
>> component)? This would be a significant performance boost..
>>
>> Wesley, your proposed modification which stores the rendered state into
>> _rendered is not good because setting _rendered will permanently
>> override the rendered EL expression, not just for the current render
>> cycle but for the lifetime of that component. What is needed is to
>> figure out when the first call to isRendered is done *during the render
>> cycle* and then cache that until rendering finishes. Note that
>> isRendered is also called during postback processing, and it's perfectly
>> reasonable to change this value between postback and render so caching
>> really should only be done between encodeBegin() and encodeEnd(). So
>> implementing this optimisation is a little tricky - but not impossible
>> I'm sure.
>>
>> Regards,
>>
>> Simon
>>
>> Andrew Robinson wrote:
>> > At the very least rendered is called during encodeBegin,
>> > encodeChildren, and encodeEnd.
>> >
>> > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
>> >> Hello - Why do we continually call isRendered after encodeBegin()?
>> >> Once the
>> >> begin tag is written out, it shouldn't matter what the body and end
>> >> rendered
>> >> states are.
>> >>
>> >> Facelets 1.1.11
>> >>  Myfaces 1.1.5 & 1.2
>> >>
>> >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
>> >> The #{MyBean.alerts method is called 5 times! and it is like this for
>> >> every
>> >> EL eval on the page. I do know that EL can only bind to the
>> >> FaceletsContext
>> >> and no other scopes... So are there any other options than what I have
>> >> listed below?
>> >>
>> >> 1. Tried to modify MyFaces src in UIComponentBase:
>> >> public boolean isRendered()
>> >>      {
>> >>            if(_rendered == null){
>> >>
>> >>            // our modification! Only compute the rendered value 
>> once, and
>> >> cache for the rest of the lifecycle.
>> >>            Boolean rend = getExpressionValue("rendered", _rendered,
>> >> DEFAULT_RENDERED);
>> >>            _rendered = rend.booleanValue();
>> >>            }
>> >>          return _rendered;
>> >>      }
>> >> This didn't work :( - Something happend to A4J and we had no ideas
>> >> what the
>> >> implication would be on all components.
>> >>
>> >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a page
>> >> scoped variable, then have the variable evaluated in the rendered
>> >> attribute.
>> >> This didn't work either because it is on FacesContext.
>> >>
>> >> So this may just be me not fully understanding  what JSF does 
>> behind the
>> >> scenes of component rendering, or some people say that  the spec is
>> >> screwed
>> >> up when it comes to this. I'm sure some of the pros can help me out
>> >> here :).
>> >>
>> >> Thx,
>> >> Wesley Hales
>>
>>


Re: Multiple calls on isRendered - Performance issue

Posted by Adam Winer <aw...@gmail.com>.
Andrew is right - you may not add public or protected methods to
UIComponent, period.  No exceptions.

IMO, the solution could look like:

public class UIComponentBase {

private Boolean _renderedCache;

private void _cacheRendered() {
  ... get rendered ...
  _renderedCache = ... ? Boolean.TRUE : Boolean.FALSE;
}

private void _flushRenderedCache() {
  _renderedCache = null;
}

public boolean isRendered() {
  if (_renderedCache != null) return _renderedCache.booleanValue();
  ...
}

public void processDecodes() {
  _flushRenderedCache();
  ...
}

public void encodeBegin() {
  _cacheRendered();

  ...
}

}

-- Adam


On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> Yeah, not sure how to approach this one... Craig or any comitters have any
> ideas?
> Thanks for the help Guys....Anybody who cares about performance will
> definitely be able to use this enhancement.
>
>
>  On 5/9/07, Andrew Robinson <an...@gmail.com> wrote:
> > Sorry for the 2 emails,
> >
> > I don't think you are allowed to add methods to the javax.faces API
> > classes. That will break TCK compatibility right? If that is true,
> > MyFaces would no longer be an official JSF provider.
> >
> > On 5/9/07, Andrew Robinson <an...@gmail.com> wrote:
> > > You may want to submit a comment for the JSF specification on changing
> > > this behavior.
> > >
> > > On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > > > So the architect I am working with (Chris Kulinski) came up with the
> > > > following patch to 1.1.5...
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIComponent.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIComponent.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIComponent.java
> > > > (working copy)
> > > > @@ -59,6 +59,8 @@
> > > >
> > > >      public abstract boolean isRendered();
> > > >
> > > > +    public abstract boolean isRenderedCached();
> > > > +
> > > >      public abstract void setRendered(boolean rendered);
> > > >
> > > >      public abstract java.lang.String getRendererType();
> > > > Index:
> src/main/java/javax/faces/component/UIMessages.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIMessages.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIMessages.java
> > > > (working copy)
> > > > @@ -28,7 +28,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIMessages
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > > --------------------
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIData.java
> > > >
> ===================================================================
> > > > --- src/main/java/javax/faces/component/UIData.java
> > > > (revision 536301)
> > > > +++ src/main/java/javax/faces/component/UIData.java
> > > > (working copy)
> > > > @@ -126,7 +126,7 @@
> > > >   * @author Manfred Geiler (latest modification by $Author$)
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > > -public class UIData extends UIComponentBase implements
> NamingContainer
> > > > +public class UIData extends UIComponentBaseCached implements
> > > > NamingContainer
> > > >  {
> > > >      private static final int STATE_SIZE = 5;
> > > >      private static final int SUPER_STATE_INDEX = 0;
> > > > @@ -577,7 +577,7 @@
> > > >      {
> > > >          if (context == null)
> > > >              throw new
> NullPointerException("context");
> > > > -        if (!isRendered())
> > > > +        if (!isRenderedCached())
> > > >              return;
> > > >          setRowIndex(-1);
> > > >          processFacets(context, PROCESS_DECODES);
> > > > @@ -599,7 +599,7 @@
> > > >      {
> > > >          if (context == null)
> > > >              throw new
> NullPointerException("context");
> > > > -        if (!isRendered())
> > > > +        if (!isRenderedCached())
> > > >              return;
> > > >          setRowIndex(-1);
> > > >          processFacets(context, PROCESS_VALIDATORS);
> > > > @@ -618,7 +618,7 @@
> > > >      {
> > > >          if (context == null)
> > > >              throw new
> NullPointerException("context");
> > > > -        if (!isRendered())
> > > > +        if (!isRenderedCached())
> > > >              return;
> > > >          setRowIndex(-1);
> > > >          processFacets(context, PROCESS_UPDATES);
> > > > @@ -656,7 +656,7 @@
> > > >              UIComponent child = (UIComponent) childIter.next();
> > > >              if (child instanceof UIColumn)
> > > >               {
> > > > -                if (!child.isRendered())
> > > > +                if (!child.isRenderedCached())
> > > >                  {
> > > >                      //Column is not visible
> > > >                      continue;
> > > > @@ -705,7 +705,7 @@
> > > >                  UIComponent child = (UIComponent) it.next();
> > > >                  if (child instanceof UIColumn)
> > > >                  {
> > > > -                    if (!child.isRendered())
> > > > +                    if (!child.isRenderedCached())
> > > >                      {
> > > >                          //Column is not visible
> > > >                          continue;
> > > > Index:
> src/main/java/javax/faces/component/UIParameter.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIParameter.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIParameter.java
> > > > (working copy)
> > > > @@ -28,7 +28,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIParameter
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > > --------------------
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIMessage.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIMessage.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIMessage.java
> > > > (working copy)
> > > > @@ -30,7 +30,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIMessage
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > > --------------------
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIForm.java
> > > >
> ===================================================================
> > > > --- src/main/java/javax/faces/component/UIForm.java
> > > > (revision 536301)
> > > > +++ src/main/java/javax/faces/component/UIForm.java
> > > > (working copy)
> > > > @@ -28,7 +28,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIForm
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >          implements NamingContainer
> > > >  {
> > > >      //private static final Log log = LogFactory.getLog(UIForm.class);
> > > > Index:
> src/main/java/javax/faces/component/UIGraphic.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIGraphic.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIGraphic.java
> > > > (working copy)
> > > > @@ -28,7 +28,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIGraphic
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      private static final String URL_PROPERTY = "url";
> > > >      private static final String VALUE_PROPERTY = "value";
> > > > Index:
> src/main/java/javax/faces/component/UICommand.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UICommand.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UICommand.java
> > > > (working copy)
> > > > @@ -31,7 +31,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >   public class UICommand
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >          implements ActionSource
> > > >  {
> > > >      private MethodBinding _action = null;
> > > > Index:
> src/main/java/javax/faces/component/UIViewRoot.java
> > > >
> ===================================================================
> > > > ---
> src/main/java/javax/faces/component/UIViewRoot.java
> > > > (revision 536301)
> > > > +++
> src/main/java/javax/faces/component/UIViewRoot.java
> > > > (working copy)
> > > > @@ -38,7 +38,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIViewRoot
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      public static final String UNIQUE_ID_PREFIX = "_id";
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIColumn.java
> > > >
> ===================================================================
> > > > --- src/main/java/javax/faces/component/UIColumn.java
> > > > (revision 536301)
> > > > +++ src/main/java/javax/faces/component/UIColumn.java
> > > > (working copy)
> > > > @@ -27,7 +27,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIColumn
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      private static final String FOOTER_FACET_NAME = "footer";
> > > >      private static final String HEADER_FACET_NAME = "header";
> > > > Index:
> > > >
> src/main/java/javax/faces/component/UIComponentBase.java
> > > >
> ===================================================================
> > > > ---
> > > >
> src/main/java/javax/faces/component/UIComponentBase.java
> > > >    (revision 536301)
> > > > +++
> > > >
> src/main/java/javax/faces/component/UIComponentBase.java
> > > >    (working copy)
> > > > @@ -508,7 +508,7 @@
> > > >              throws IOException
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -        if (!isRendered()) return;
> > > > +        if (!isRenderedCached()) return;
> > > >          Renderer renderer = getRenderer(context);
> > > >          if (renderer != null)
> > > >          {
> > > > @@ -520,7 +520,7 @@
> > > >              throws IOException
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -        if (!isRendered()) return;
> > > > +        if (!isRenderedCached()) return;
> > > >          Renderer renderer = getRenderer(context);
> > > >          if (renderer != null)
> > > >          {
> > > > @@ -532,7 +532,7 @@
> > > >              throws IOException
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -        if (!isRendered()) return;
> > > > +        if (!isRenderedCached()) return;
> > > >          Renderer renderer = getRenderer(context);
> > > >          if (renderer != null)
> > > >          {
> > > > @@ -598,7 +598,7 @@
> > > >      public void processDecodes(FacesContext context)
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -                if (!isRendered()) return;
> > > > +                if (!isRenderedCached()) return;
> > > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > > >          {
> > > >              UIComponent childOrFacet = (UIComponent)it.next();
> > > > @@ -619,7 +619,7 @@
> > > >      public void processValidators(FacesContext context)
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -        if (!isRendered()) return;
> > > > +        if (!isRenderedCached()) return;
> > > >
> > > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > > >          {
> > > > @@ -640,7 +640,7 @@
> > > >      public void processUpdates(FacesContext context)
> > > >      {
> > > >          if (context == null) throw new
> > > > NullPointerException("context");
> > > > -        if (!isRendered()) return;
> > > > +        if (!isRenderedCached()) return;
> > > >
> > > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > > >          {
> > > > @@ -1063,6 +1063,7 @@
> > > >
> > > >      private Boolean _rendered = null;
> > > >      private String _rendererType = null;
> > > > +    private Boolean _renderedCached = null;
> > > >
> > > >
> > > >
> > > > @@ -1072,11 +1073,29 @@
> > > >      }
> > > >
> > > >      public boolean isRendered()
> > > > +    {
> > > > +        if (_rendered != null) return _rendered.booleanValue();
> > > > +        ValueBinding vb = getValueBinding("rendered");
> > > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > > multiple times.
> > > > +        _renderedCached = vb != null ?
> > > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > > +        return _renderedCached != null ?
> _renderedCached.booleanValue() :
> > > > DEFAULT_RENDERED;
> > > > +    }
> > > > +
> > > > +    public boolean isRenderedCached()
> > > >      {
> > > >          if (_rendered != null) return _rendered.booleanValue();
> > > > +
> > > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > > multiple times.
> > > > +        if (_renderedCached != null) {
> > > > +            //System.out.println("using CACHED value
> for:"+getId()+"
> > > > "+this);
> > > > +            return _renderedCached.booleanValue();
> > > > +        }
> > > > +
> > > >          ValueBinding vb = getValueBinding("rendered");
> > > > -        Boolean v = vb != null ?
> > > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > > -        return v != null ? v.booleanValue() : DEFAULT_RENDERED;
> > > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > > multiple times.
> > > > +        _renderedCached = vb != null ?
> > > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > > +        //System.out.println("Computing NO CACHE
> value for:"+getId()+"
> > > > "+this);
> > > > +        return _renderedCached != null ?
> _renderedCached.booleanValue() :
> > > > DEFAULT_RENDERED;
> > > >      }
> > > >
> > > >      public void setRendererType(String rendererType)
> > > > Index:
> src/main/java/javax/faces/component/UIPanel.java
> > > >
> ===================================================================
> > > > --- src/main/java/javax/faces/component/UIPanel.java
> > > > (revision 536301)
> > > > +++ src/main/java/javax/faces/component/UIPanel.java
> > > > (working copy)
> > > > @@ -27,7 +27,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIPanel
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >  {
> > > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > > --------------------
> > > >
> > > > Index:
> src/main/java/javax/faces/component/UIOutput.java
> > > >
> ===================================================================
> > > > --- src/main/java/javax/faces/component/UIOutput.java
> > > > (revision 536301)
> > > > +++ src/main/java/javax/faces/component/UIOutput.java
> > > > (working copy)
> > > > @@ -29,7 +29,7 @@
> > > >   * @version $Revision$ $Date$
> > > >   */
> > > >  public class UIOutput
> > > > -        extends UIComponentBase
> > > > +        extends UIComponentBaseCached
> > > >          implements ValueHolder
> > > >  {
> > > >      public Object getLocalValue()
> > > >
> ---------------------------------------------------------------------------------
> > > >
> > > > and here is the UIComponentBaseCached class:
> > > >
> > > > package javax.faces.component ;
> > > >
> > > > public abstract class UIComponentBaseCached extends UIComponentBase {
> > > >
> > > >     public boolean isRendered()
> > > >     {
> > > >         return isRenderedCached();
> > > >     }
> > > > }
> > > >
> > > >
> > > > So far so good, I will post the results if anything stops working.
> > > >
> > > > Wesley
> > > >
> > > >
> > > >
> > > >
> > > >  On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > > > > I am trying to address this at a framework level (i.e. I'm not
> rewriting
> > > > the renderer for each component that calls an EL method)
> > > > >
> > > > >
> > > > >
> > > > > On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
> > > > > > Technically, rendered is supposed to be:
> > > > > > - Constant across
> > > > encodeBegin()/encodeChildren()/encodeEnd()
> > > > > > - Constant across
> processDecodes()/processValidators()/
> > > > > >    processUpdateModel().
> > > > > >
> > > > > > Unfortunately, the latter doesn't help - since a component inside
> > > > > > a table would have processDecodes() called repeatedly,
> > > > > > then processValidators() repeatedly, etc. - and "rendered"
> > > > > > could be different from one row to the next.
> > > > > >
> > > > > > But the former should be fine - if you always fetch and
> > > > > > store the value in encodeBegin() (whether or not encodeBegin()
> > > > > > has previously been called), then use that in encodeChildren()
> > > > > > and encodeEnd(), you should be fine.
> > > > > >
> > > > > > -- Adam
> > > > > >
> > > > > >
> > > > > > On 5/8/07, Simon Kitching < simon.kitching@rhe.co.nz> wrote:
> > > > > > > Andrew, are you just stating what currently happens or are you
> saying
> > > > > > > that there is a *reason* for evaluating "rendered" in
> encodeBegin,
> > > > > > > encodeChildren and encodeEnd?
> > > > > > >
> > > > > > > I can't initially see any reason why it would need to be
> evaluated
> > > > more
> > > > > > > than once.
> > > > > > >
> > > > > > > UIComponentBase does indeed call isRendered in encodeBegin,
> > > > > > > encodeChildren and encodeEnd. It also implements isRendered as
> an
> > > > > > > evaluation of the EL expression (myfaces 1.1.3 implementation).
> > > > > > >
> > > > > > > But As Wesley asks, why would it ever make sense for rendered to
> be
> > > > true
> > > > > > > in encodeBegin, but false in encodeEnd? I cannot see any way
> that
> > > > would
> > > > > > > be useful, so why not just compute it once then cache it
> somewhere for
> > > > > > > the rest of that render cycle (eg in a "transient" member of the
> > > > > > > component)? This would be a significant performance boost..
> > > > > > >
> > > > > > > Wesley, your proposed modification which stores the rendered
> state
> > > > into
> > > > > > > _rendered is not good because setting _rendered will permanently
> > > > > > > override the rendered EL expression, not just for the current
> render
> > > > > > > cycle but for the lifetime of that component. What is needed is
> to
> > > > > > > figure out when the first call to isRendered is done *during the
> > > > render
> > > > > > > cycle* and then cache that until rendering finishes. Note that
> > > > > > > isRendered is also called during postback processing, and it's
> > > > perfectly
> > > > > > > reasonable to change this value between postback and render so
> caching
> > > > > > > really should only be done between encodeBegin() and
> encodeEnd(). So
> > > > > > > implementing this optimisation is a little tricky - but not
> impossible
> > > > > > > I'm sure.
> > > > > > >
> > > > > > > Regards,
> > > > > > >
> > > > > > > Simon
> > > > > > >
> > > > > > > Andrew Robinson wrote:
> > > > > > > > At the very least rendered is called during encodeBegin,
> > > > > > > > encodeChildren, and encodeEnd.
> > > > > > > >
> > > > > > > > On 5/8/07, Wesley Hales < wesleyhales@gmail.com> wrote:
> > > > > > > >> Hello - Why do we continually call isRendered after
> encodeBegin()?
> > > > > > > >> Once the
> > > > > > > >> begin tag is written out, it shouldn't matter what the body
> and end
> > > > > > > >> rendered
> > > > > > > >> states are.
> > > > > > > >>
> > > > > > > >> Facelets 1.1.11
> > > > > > > >>  Myfaces 1.1.5 & 1.2
> > > > > > > >>
> > > > > > > >> So if I have  <t:div rendered="#{ MyBean.alerts > 0}"...
> > > > > > > >> The #{MyBean.alerts method is called 5 times! and it is like
> this
> > > > for
> > > > > > > >> every
> > > > > > > >> EL eval on the page. I do know that EL can only bind to the
> > > > > > > >> FaceletsContext
> > > > > > > >> and no other scopes... So are there any other options than
> what I
> > > > have
> > > > > > > >> listed below?
> > > > > > > >>
> > > > > > > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > > > > > >> public boolean isRendered()
> > > > > > > >>      {
> > > > > > > >>            if(_rendered == null){
> > > > > > > >>
> > > > > > > >>            // our modification! Only compute the rendered
> value
> > > > once, and
> > > > > > > >> cache for the rest of the lifecycle.
> > > > > > > >>            Boolean rend = getExpressionValue("rendered",
> _rendered,
> > > > > > > >> DEFAULT_RENDERED);
> > > > > > > >>            _rendered = rend.booleanValue();
> > > > > > > >>            }
> > > > > > > >>          return _rendered;
> > > > > > > >>      }
> > > > > > > >> This didn't work :( - Something happend to A4J and we had no
> ideas
> > > > > > > >> what the
> > > > > > > >> implication would be on all components.
> > > > > > > >>
> > > > > > > >> 2. Tried using Facelets <ui:param and <c:set to store the EL
> in a
> > > > page
> > > > > > > >> scoped variable, then have the variable evaluated in the
> rendered
> > > > > > > >> attribute.
> > > > > > > >> This didn't work either because it is on FacesContext.
> > > > > > > >>
> > > > > > > >> So this may just be me not fully understanding  what JSF does
> > > > behind the
> > > > > > > >> scenes of component rendering, or some people say that  the
> spec is
> > > > > > > >> screwed
> > > > > > > >> up when it comes to this. I'm sure some of the pros can help
> me out
> > > > > > > >> here :).
> > > > > > > >>
> > > > > > > >> Thx,
> > > > > > > >> Wesley Hales
> > > > > > >
> > > > > > >
> > > > > >
> > > > >
> > > > >
> > > >
> > > >
> > >
> >
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Wesley Hales <we...@gmail.com>.
Yeah, not sure how to approach this one... Craig or any comitters have any
ideas?
Thanks for the help Guys....Anybody who cares about performance will
definitely be able to use this enhancement.

On 5/9/07, Andrew Robinson <an...@gmail.com> wrote:
>
> Sorry for the 2 emails,
>
> I don't think you are allowed to add methods to the javax.faces API
> classes. That will break TCK compatibility right? If that is true,
> MyFaces would no longer be an official JSF provider.
>
> On 5/9/07, Andrew Robinson <an...@gmail.com> wrote:
> > You may want to submit a comment for the JSF specification on changing
> > this behavior.
> >
> > On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > > So the architect I am working with (Chris Kulinski) came up with the
> > > following patch to 1.1.5...
> > >
> > > Index: src/main/java/javax/faces/component/UIComponent.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIComponent.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIComponent.java
> > > (working copy)
> > > @@ -59,6 +59,8 @@
> > >
> > >      public abstract boolean isRendered();
> > >
> > > +    public abstract boolean isRenderedCached();
> > > +
> > >      public abstract void setRendered(boolean rendered);
> > >
> > >      public abstract java.lang.String getRendererType();
> > > Index: src/main/java/javax/faces/component/UIMessages.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIMessages.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIMessages.java
> > > (working copy)
> > > @@ -28,7 +28,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIMessages
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > --------------------
> > >
> > > Index: src/main/java/javax/faces/component/UIData.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIData.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIData.java
> > > (working copy)
> > > @@ -126,7 +126,7 @@
> > >   * @author Manfred Geiler (latest modification by $Author$)
> > >   * @version $Revision$ $Date$
> > >   */
> > > -public class UIData extends UIComponentBase implements
> NamingContainer
> > > +public class UIData extends UIComponentBaseCached implements
> > > NamingContainer
> > >  {
> > >      private static final int STATE_SIZE = 5;
> > >      private static final int SUPER_STATE_INDEX = 0;
> > > @@ -577,7 +577,7 @@
> > >      {
> > >          if (context == null)
> > >              throw new NullPointerException("context");
> > > -        if (!isRendered())
> > > +        if (!isRenderedCached())
> > >              return;
> > >          setRowIndex(-1);
> > >          processFacets(context, PROCESS_DECODES);
> > > @@ -599,7 +599,7 @@
> > >      {
> > >          if (context == null)
> > >              throw new NullPointerException("context");
> > > -        if (!isRendered())
> > > +        if (!isRenderedCached())
> > >              return;
> > >          setRowIndex(-1);
> > >          processFacets(context, PROCESS_VALIDATORS);
> > > @@ -618,7 +618,7 @@
> > >      {
> > >          if (context == null)
> > >              throw new NullPointerException("context");
> > > -        if (!isRendered())
> > > +        if (!isRenderedCached())
> > >              return;
> > >          setRowIndex(-1);
> > >          processFacets(context, PROCESS_UPDATES);
> > > @@ -656,7 +656,7 @@
> > >              UIComponent child = (UIComponent) childIter.next();
> > >              if (child instanceof UIColumn)
> > >               {
> > > -                if (!child.isRendered())
> > > +                if (!child.isRenderedCached())
> > >                  {
> > >                      //Column is not visible
> > >                      continue;
> > > @@ -705,7 +705,7 @@
> > >                  UIComponent child = (UIComponent) it.next();
> > >                  if (child instanceof UIColumn)
> > >                  {
> > > -                    if (!child.isRendered())
> > > +                    if (!child.isRenderedCached())
> > >                      {
> > >                          //Column is not visible
> > >                          continue;
> > > Index: src/main/java/javax/faces/component/UIParameter.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIParameter.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIParameter.java
> > > (working copy)
> > > @@ -28,7 +28,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIParameter
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > --------------------
> > >
> > > Index: src/main/java/javax/faces/component/UIMessage.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIMessage.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIMessage.java
> > > (working copy)
> > > @@ -30,7 +30,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIMessage
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > --------------------
> > >
> > > Index: src/main/java/javax/faces/component/UIForm.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIForm.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIForm.java
> > > (working copy)
> > > @@ -28,7 +28,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIForm
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >          implements NamingContainer
> > >  {
> > >      //private static final Log log = LogFactory.getLog(UIForm.class);
> > > Index: src/main/java/javax/faces/component/UIGraphic.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIGraphic.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIGraphic.java
> > > (working copy)
> > > @@ -28,7 +28,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIGraphic
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      private static final String URL_PROPERTY = "url";
> > >      private static final String VALUE_PROPERTY = "value";
> > > Index: src/main/java/javax/faces/component/UICommand.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UICommand.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UICommand.java
> > > (working copy)
> > > @@ -31,7 +31,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >   public class UICommand
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >          implements ActionSource
> > >  {
> > >      private MethodBinding _action = null;
> > > Index: src/main/java/javax/faces/component/UIViewRoot.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIViewRoot.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIViewRoot.java
> > > (working copy)
> > > @@ -38,7 +38,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIViewRoot
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      public static final String UNIQUE_ID_PREFIX = "_id";
> > >
> > > Index: src/main/java/javax/faces/component/UIColumn.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIColumn.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIColumn.java
> > > (working copy)
> > > @@ -27,7 +27,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIColumn
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      private static final String FOOTER_FACET_NAME = "footer";
> > >      private static final String HEADER_FACET_NAME = "header";
> > > Index:
> > > src/main/java/javax/faces/component/UIComponentBase.java
> > > ===================================================================
> > > ---
> > > src/main/java/javax/faces/component/UIComponentBase.java
> > >    (revision 536301)
> > > +++
> > > src/main/java/javax/faces/component/UIComponentBase.java
> > >    (working copy)
> > > @@ -508,7 +508,7 @@
> > >              throws IOException
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -        if (!isRendered()) return;
> > > +        if (!isRenderedCached()) return;
> > >          Renderer renderer = getRenderer(context);
> > >          if (renderer != null)
> > >          {
> > > @@ -520,7 +520,7 @@
> > >              throws IOException
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -        if (!isRendered()) return;
> > > +        if (!isRenderedCached()) return;
> > >          Renderer renderer = getRenderer(context);
> > >          if (renderer != null)
> > >          {
> > > @@ -532,7 +532,7 @@
> > >              throws IOException
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -        if (!isRendered()) return;
> > > +        if (!isRenderedCached()) return;
> > >          Renderer renderer = getRenderer(context);
> > >          if (renderer != null)
> > >          {
> > > @@ -598,7 +598,7 @@
> > >      public void processDecodes(FacesContext context)
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -                if (!isRendered()) return;
> > > +                if (!isRenderedCached()) return;
> > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > >          {
> > >              UIComponent childOrFacet = (UIComponent)it.next();
> > > @@ -619,7 +619,7 @@
> > >      public void processValidators(FacesContext context)
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -        if (!isRendered()) return;
> > > +        if (!isRenderedCached()) return;
> > >
> > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > >          {
> > > @@ -640,7 +640,7 @@
> > >      public void processUpdates(FacesContext context)
> > >      {
> > >          if (context == null) throw new
> > > NullPointerException("context");
> > > -        if (!isRendered()) return;
> > > +        if (!isRenderedCached()) return;
> > >
> > >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> > >          {
> > > @@ -1063,6 +1063,7 @@
> > >
> > >      private Boolean _rendered = null;
> > >      private String _rendererType = null;
> > > +    private Boolean _renderedCached = null;
> > >
> > >
> > >
> > > @@ -1072,11 +1073,29 @@
> > >      }
> > >
> > >      public boolean isRendered()
> > > +    {
> > > +        if (_rendered != null) return _rendered.booleanValue();
> > > +        ValueBinding vb = getValueBinding("rendered");
> > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > multiple times.
> > > +        _renderedCached = vb != null ?
> > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > +        return _renderedCached != null ?
> _renderedCached.booleanValue() :
> > > DEFAULT_RENDERED;
> > > +    }
> > > +
> > > +    public boolean isRenderedCached()
> > >      {
> > >          if (_rendered != null) return _rendered.booleanValue();
> > > +
> > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > multiple times.
> > > +        if (_renderedCached != null) {
> > > +            //System.out.println("using CACHED value for:"+getId()+"
> > > "+this);
> > > +            return _renderedCached.booleanValue();
> > > +        }
> > > +
> > >          ValueBinding vb = getValueBinding("rendered");
> > > -        Boolean v = vb != null ?
> > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > -        return v != null ? v.booleanValue() : DEFAULT_RENDERED;
> > > +        // AUTOTRADER: Cache the rendered value so its not computed
> > > multiple times.
> > > +        _renderedCached = vb != null ?
> > > (Boolean)vb.getValue(getFacesContext()) : null;
> > > +        //System.out.println("Computing NO CACHE value
> for:"+getId()+"
> > > "+this);
> > > +        return _renderedCached != null ?
> _renderedCached.booleanValue() :
> > > DEFAULT_RENDERED;
> > >      }
> > >
> > >      public void setRendererType(String rendererType)
> > > Index: src/main/java/javax/faces/component/UIPanel.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIPanel.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIPanel.java
> > > (working copy)
> > > @@ -27,7 +27,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIPanel
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >  {
> > >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > > --------------------
> > >
> > > Index: src/main/java/javax/faces/component/UIOutput.java
> > > ===================================================================
> > > --- src/main/java/javax/faces/component/UIOutput.java
> > > (revision 536301)
> > > +++ src/main/java/javax/faces/component/UIOutput.java
> > > (working copy)
> > > @@ -29,7 +29,7 @@
> > >   * @version $Revision$ $Date$
> > >   */
> > >  public class UIOutput
> > > -        extends UIComponentBase
> > > +        extends UIComponentBaseCached
> > >          implements ValueHolder
> > >  {
> > >      public Object getLocalValue()
> > >
> ---------------------------------------------------------------------------------
> > >
> > > and here is the UIComponentBaseCached class:
> > >
> > > package javax.faces.component;
> > >
> > > public abstract class UIComponentBaseCached extends UIComponentBase {
> > >
> > >     public boolean isRendered()
> > >     {
> > >         return isRenderedCached();
> > >     }
> > > }
> > >
> > >
> > > So far so good, I will post the results if anything stops working.
> > >
> > > Wesley
> > >
> > >
> > >
> > >
> > >  On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > > > I am trying to address this at a framework level (i.e. I'm not
> rewriting
> > > the renderer for each component that calls an EL method)
> > > >
> > > >
> > > >
> > > > On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
> > > > > Technically, rendered is supposed to be:
> > > > > - Constant across
> > > encodeBegin()/encodeChildren()/encodeEnd()
> > > > > - Constant across processDecodes()/processValidators()/
> > > > >    processUpdateModel().
> > > > >
> > > > > Unfortunately, the latter doesn't help - since a component inside
> > > > > a table would have processDecodes() called repeatedly,
> > > > > then processValidators() repeatedly, etc. - and "rendered"
> > > > > could be different from one row to the next.
> > > > >
> > > > > But the former should be fine - if you always fetch and
> > > > > store the value in encodeBegin() (whether or not encodeBegin()
> > > > > has previously been called), then use that in encodeChildren()
> > > > > and encodeEnd(), you should be fine.
> > > > >
> > > > > -- Adam
> > > > >
> > > > >
> > > > > On 5/8/07, Simon Kitching < simon.kitching@rhe.co.nz> wrote:
> > > > > > Andrew, are you just stating what currently happens or are you
> saying
> > > > > > that there is a *reason* for evaluating "rendered" in
> encodeBegin,
> > > > > > encodeChildren and encodeEnd?
> > > > > >
> > > > > > I can't initially see any reason why it would need to be
> evaluated
> > > more
> > > > > > than once.
> > > > > >
> > > > > > UIComponentBase does indeed call isRendered in encodeBegin,
> > > > > > encodeChildren and encodeEnd. It also implements isRendered as
> an
> > > > > > evaluation of the EL expression (myfaces 1.1.3 implementation).
> > > > > >
> > > > > > But As Wesley asks, why would it ever make sense for rendered to
> be
> > > true
> > > > > > in encodeBegin, but false in encodeEnd? I cannot see any way
> that
> > > would
> > > > > > be useful, so why not just compute it once then cache it
> somewhere for
> > > > > > the rest of that render cycle (eg in a "transient" member of the
> > > > > > component)? This would be a significant performance boost..
> > > > > >
> > > > > > Wesley, your proposed modification which stores the rendered
> state
> > > into
> > > > > > _rendered is not good because setting _rendered will permanently
> > > > > > override the rendered EL expression, not just for the current
> render
> > > > > > cycle but for the lifetime of that component. What is needed is
> to
> > > > > > figure out when the first call to isRendered is done *during the
> > > render
> > > > > > cycle* and then cache that until rendering finishes. Note that
> > > > > > isRendered is also called during postback processing, and it's
> > > perfectly
> > > > > > reasonable to change this value between postback and render so
> caching
> > > > > > really should only be done between encodeBegin() and
> encodeEnd(). So
> > > > > > implementing this optimisation is a little tricky - but not
> impossible
> > > > > > I'm sure.
> > > > > >
> > > > > > Regards,
> > > > > >
> > > > > > Simon
> > > > > >
> > > > > > Andrew Robinson wrote:
> > > > > > > At the very least rendered is called during encodeBegin,
> > > > > > > encodeChildren, and encodeEnd.
> > > > > > >
> > > > > > > On 5/8/07, Wesley Hales < wesleyhales@gmail.com> wrote:
> > > > > > >> Hello - Why do we continually call isRendered after
> encodeBegin()?
> > > > > > >> Once the
> > > > > > >> begin tag is written out, it shouldn't matter what the body
> and end
> > > > > > >> rendered
> > > > > > >> states are.
> > > > > > >>
> > > > > > >> Facelets 1.1.11
> > > > > > >>  Myfaces 1.1.5 & 1.2
> > > > > > >>
> > > > > > >> So if I have  <t:div rendered="#{ MyBean.alerts > 0}"...
> > > > > > >> The #{MyBean.alerts method is called 5 times! and it is like
> this
> > > for
> > > > > > >> every
> > > > > > >> EL eval on the page. I do know that EL can only bind to the
> > > > > > >> FaceletsContext
> > > > > > >> and no other scopes... So are there any other options than
> what I
> > > have
> > > > > > >> listed below?
> > > > > > >>
> > > > > > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > > > > >> public boolean isRendered()
> > > > > > >>      {
> > > > > > >>            if(_rendered == null){
> > > > > > >>
> > > > > > >>            // our modification! Only compute the rendered
> value
> > > once, and
> > > > > > >> cache for the rest of the lifecycle.
> > > > > > >>            Boolean rend = getExpressionValue("rendered",
> _rendered,
> > > > > > >> DEFAULT_RENDERED);
> > > > > > >>            _rendered = rend.booleanValue();
> > > > > > >>            }
> > > > > > >>          return _rendered;
> > > > > > >>      }
> > > > > > >> This didn't work :( - Something happend to A4J and we had no
> ideas
> > > > > > >> what the
> > > > > > >> implication would be on all components.
> > > > > > >>
> > > > > > >> 2. Tried using Facelets <ui:param and <c:set to store the EL
> in a
> > > page
> > > > > > >> scoped variable, then have the variable evaluated in the
> rendered
> > > > > > >> attribute.
> > > > > > >> This didn't work either because it is on FacesContext.
> > > > > > >>
> > > > > > >> So this may just be me not fully understanding  what JSF does
> > > behind the
> > > > > > >> scenes of component rendering, or some people say that  the
> spec is
> > > > > > >> screwed
> > > > > > >> up when it comes to this. I'm sure some of the pros can help
> me out
> > > > > > >> here :).
> > > > > > >>
> > > > > > >> Thx,
> > > > > > >> Wesley Hales
> > > > > >
> > > > > >
> > > > >
> > > >
> > > >
> > >
> > >
> >
>

Re: Multiple calls on isRendered - Performance issue

Posted by Andrew Robinson <an...@gmail.com>.
Sorry for the 2 emails,

I don't think you are allowed to add methods to the javax.faces API
classes. That will break TCK compatibility right? If that is true,
MyFaces would no longer be an official JSF provider.

On 5/9/07, Andrew Robinson <an...@gmail.com> wrote:
> You may want to submit a comment for the JSF specification on changing
> this behavior.
>
> On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > So the architect I am working with (Chris Kulinski) came up with the
> > following patch to 1.1.5...
> >
> > Index: src/main/java/javax/faces/component/UIComponent.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIComponent.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIComponent.java
> > (working copy)
> > @@ -59,6 +59,8 @@
> >
> >      public abstract boolean isRendered();
> >
> > +    public abstract boolean isRenderedCached();
> > +
> >      public abstract void setRendered(boolean rendered);
> >
> >      public abstract java.lang.String getRendererType();
> > Index: src/main/java/javax/faces/component/UIMessages.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIMessages.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIMessages.java
> > (working copy)
> > @@ -28,7 +28,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIMessages
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > --------------------
> >
> > Index: src/main/java/javax/faces/component/UIData.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIData.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIData.java
> > (working copy)
> > @@ -126,7 +126,7 @@
> >   * @author Manfred Geiler (latest modification by $Author$)
> >   * @version $Revision$ $Date$
> >   */
> > -public class UIData extends UIComponentBase implements NamingContainer
> > +public class UIData extends UIComponentBaseCached implements
> > NamingContainer
> >  {
> >      private static final int STATE_SIZE = 5;
> >      private static final int SUPER_STATE_INDEX = 0;
> > @@ -577,7 +577,7 @@
> >      {
> >          if (context == null)
> >              throw new NullPointerException("context");
> > -        if (!isRendered())
> > +        if (!isRenderedCached())
> >              return;
> >          setRowIndex(-1);
> >          processFacets(context, PROCESS_DECODES);
> > @@ -599,7 +599,7 @@
> >      {
> >          if (context == null)
> >              throw new NullPointerException("context");
> > -        if (!isRendered())
> > +        if (!isRenderedCached())
> >              return;
> >          setRowIndex(-1);
> >          processFacets(context, PROCESS_VALIDATORS);
> > @@ -618,7 +618,7 @@
> >      {
> >          if (context == null)
> >              throw new NullPointerException("context");
> > -        if (!isRendered())
> > +        if (!isRenderedCached())
> >              return;
> >          setRowIndex(-1);
> >          processFacets(context, PROCESS_UPDATES);
> > @@ -656,7 +656,7 @@
> >              UIComponent child = (UIComponent) childIter.next();
> >              if (child instanceof UIColumn)
> >               {
> > -                if (!child.isRendered())
> > +                if (!child.isRenderedCached())
> >                  {
> >                      //Column is not visible
> >                      continue;
> > @@ -705,7 +705,7 @@
> >                  UIComponent child = (UIComponent) it.next();
> >                  if (child instanceof UIColumn)
> >                  {
> > -                    if (!child.isRendered())
> > +                    if (!child.isRenderedCached())
> >                      {
> >                          //Column is not visible
> >                          continue;
> > Index: src/main/java/javax/faces/component/UIParameter.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIParameter.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIParameter.java
> > (working copy)
> > @@ -28,7 +28,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIParameter
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > --------------------
> >
> > Index: src/main/java/javax/faces/component/UIMessage.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIMessage.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIMessage.java
> > (working copy)
> > @@ -30,7 +30,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIMessage
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > --------------------
> >
> > Index: src/main/java/javax/faces/component/UIForm.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIForm.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIForm.java
> > (working copy)
> > @@ -28,7 +28,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIForm
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >          implements NamingContainer
> >  {
> >      //private static final Log log = LogFactory.getLog(UIForm.class);
> > Index: src/main/java/javax/faces/component/UIGraphic.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIGraphic.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIGraphic.java
> > (working copy)
> > @@ -28,7 +28,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIGraphic
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      private static final String URL_PROPERTY = "url";
> >      private static final String VALUE_PROPERTY = "value";
> > Index: src/main/java/javax/faces/component/UICommand.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UICommand.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UICommand.java
> > (working copy)
> > @@ -31,7 +31,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >   public class UICommand
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >          implements ActionSource
> >  {
> >      private MethodBinding _action = null;
> > Index: src/main/java/javax/faces/component/UIViewRoot.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIViewRoot.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIViewRoot.java
> > (working copy)
> > @@ -38,7 +38,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIViewRoot
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      public static final String UNIQUE_ID_PREFIX = "_id";
> >
> > Index: src/main/java/javax/faces/component/UIColumn.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIColumn.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIColumn.java
> > (working copy)
> > @@ -27,7 +27,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIColumn
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      private static final String FOOTER_FACET_NAME = "footer";
> >      private static final String HEADER_FACET_NAME = "header";
> > Index:
> > src/main/java/javax/faces/component/UIComponentBase.java
> > ===================================================================
> > ---
> > src/main/java/javax/faces/component/UIComponentBase.java
> >    (revision 536301)
> > +++
> > src/main/java/javax/faces/component/UIComponentBase.java
> >    (working copy)
> > @@ -508,7 +508,7 @@
> >              throws IOException
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -        if (!isRendered()) return;
> > +        if (!isRenderedCached()) return;
> >          Renderer renderer = getRenderer(context);
> >          if (renderer != null)
> >          {
> > @@ -520,7 +520,7 @@
> >              throws IOException
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -        if (!isRendered()) return;
> > +        if (!isRenderedCached()) return;
> >          Renderer renderer = getRenderer(context);
> >          if (renderer != null)
> >          {
> > @@ -532,7 +532,7 @@
> >              throws IOException
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -        if (!isRendered()) return;
> > +        if (!isRenderedCached()) return;
> >          Renderer renderer = getRenderer(context);
> >          if (renderer != null)
> >          {
> > @@ -598,7 +598,7 @@
> >      public void processDecodes(FacesContext context)
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -                if (!isRendered()) return;
> > +                if (!isRenderedCached()) return;
> >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> >          {
> >              UIComponent childOrFacet = (UIComponent)it.next();
> > @@ -619,7 +619,7 @@
> >      public void processValidators(FacesContext context)
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -        if (!isRendered()) return;
> > +        if (!isRenderedCached()) return;
> >
> >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> >          {
> > @@ -640,7 +640,7 @@
> >      public void processUpdates(FacesContext context)
> >      {
> >          if (context == null) throw new
> > NullPointerException("context");
> > -        if (!isRendered()) return;
> > +        if (!isRenderedCached()) return;
> >
> >          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
> >          {
> > @@ -1063,6 +1063,7 @@
> >
> >      private Boolean _rendered = null;
> >      private String _rendererType = null;
> > +    private Boolean _renderedCached = null;
> >
> >
> >
> > @@ -1072,11 +1073,29 @@
> >      }
> >
> >      public boolean isRendered()
> > +    {
> > +        if (_rendered != null) return _rendered.booleanValue();
> > +        ValueBinding vb = getValueBinding("rendered");
> > +        // AUTOTRADER: Cache the rendered value so its not computed
> > multiple times.
> > +        _renderedCached = vb != null ?
> > (Boolean)vb.getValue(getFacesContext()) : null;
> > +        return _renderedCached != null ? _renderedCached.booleanValue() :
> > DEFAULT_RENDERED;
> > +    }
> > +
> > +    public boolean isRenderedCached()
> >      {
> >          if (_rendered != null) return _rendered.booleanValue();
> > +
> > +        // AUTOTRADER: Cache the rendered value so its not computed
> > multiple times.
> > +        if (_renderedCached != null) {
> > +            //System.out.println("using CACHED value for:"+getId()+"
> > "+this);
> > +            return _renderedCached.booleanValue();
> > +        }
> > +
> >          ValueBinding vb = getValueBinding("rendered");
> > -        Boolean v = vb != null ?
> > (Boolean)vb.getValue(getFacesContext()) : null;
> > -        return v != null ? v.booleanValue() : DEFAULT_RENDERED;
> > +        // AUTOTRADER: Cache the rendered value so its not computed
> > multiple times.
> > +        _renderedCached = vb != null ?
> > (Boolean)vb.getValue(getFacesContext()) : null;
> > +        //System.out.println("Computing NO CACHE value for:"+getId()+"
> > "+this);
> > +        return _renderedCached != null ? _renderedCached.booleanValue() :
> > DEFAULT_RENDERED;
> >      }
> >
> >      public void setRendererType(String rendererType)
> > Index: src/main/java/javax/faces/component/UIPanel.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIPanel.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIPanel.java
> > (working copy)
> > @@ -27,7 +27,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIPanel
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >  {
> >      //------------------ GENERATED CODE BEGIN (do not modify!)
> > --------------------
> >
> > Index: src/main/java/javax/faces/component/UIOutput.java
> > ===================================================================
> > --- src/main/java/javax/faces/component/UIOutput.java
> > (revision 536301)
> > +++ src/main/java/javax/faces/component/UIOutput.java
> > (working copy)
> > @@ -29,7 +29,7 @@
> >   * @version $Revision$ $Date$
> >   */
> >  public class UIOutput
> > -        extends UIComponentBase
> > +        extends UIComponentBaseCached
> >          implements ValueHolder
> >  {
> >      public Object getLocalValue()
> > ---------------------------------------------------------------------------------
> >
> > and here is the UIComponentBaseCached class:
> >
> > package javax.faces.component;
> >
> > public abstract class UIComponentBaseCached extends UIComponentBase {
> >
> >     public boolean isRendered()
> >     {
> >         return isRenderedCached();
> >     }
> > }
> >
> >
> > So far so good, I will post the results if anything stops working.
> >
> > Wesley
> >
> >
> >
> >
> >  On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > > I am trying to address this at a framework level (i.e. I'm not rewriting
> > the renderer for each component that calls an EL method)
> > >
> > >
> > >
> > > On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
> > > > Technically, rendered is supposed to be:
> > > > - Constant across
> > encodeBegin()/encodeChildren()/encodeEnd()
> > > > - Constant across processDecodes()/processValidators()/
> > > >    processUpdateModel().
> > > >
> > > > Unfortunately, the latter doesn't help - since a component inside
> > > > a table would have processDecodes() called repeatedly,
> > > > then processValidators() repeatedly, etc. - and "rendered"
> > > > could be different from one row to the next.
> > > >
> > > > But the former should be fine - if you always fetch and
> > > > store the value in encodeBegin() (whether or not encodeBegin()
> > > > has previously been called), then use that in encodeChildren()
> > > > and encodeEnd(), you should be fine.
> > > >
> > > > -- Adam
> > > >
> > > >
> > > > On 5/8/07, Simon Kitching < simon.kitching@rhe.co.nz> wrote:
> > > > > Andrew, are you just stating what currently happens or are you saying
> > > > > that there is a *reason* for evaluating "rendered" in encodeBegin,
> > > > > encodeChildren and encodeEnd?
> > > > >
> > > > > I can't initially see any reason why it would need to be evaluated
> > more
> > > > > than once.
> > > > >
> > > > > UIComponentBase does indeed call isRendered in encodeBegin,
> > > > > encodeChildren and encodeEnd. It also implements isRendered as an
> > > > > evaluation of the EL expression (myfaces 1.1.3 implementation).
> > > > >
> > > > > But As Wesley asks, why would it ever make sense for rendered to be
> > true
> > > > > in encodeBegin, but false in encodeEnd? I cannot see any way that
> > would
> > > > > be useful, so why not just compute it once then cache it somewhere for
> > > > > the rest of that render cycle (eg in a "transient" member of the
> > > > > component)? This would be a significant performance boost..
> > > > >
> > > > > Wesley, your proposed modification which stores the rendered state
> > into
> > > > > _rendered is not good because setting _rendered will permanently
> > > > > override the rendered EL expression, not just for the current render
> > > > > cycle but for the lifetime of that component. What is needed is to
> > > > > figure out when the first call to isRendered is done *during the
> > render
> > > > > cycle* and then cache that until rendering finishes. Note that
> > > > > isRendered is also called during postback processing, and it's
> > perfectly
> > > > > reasonable to change this value between postback and render so caching
> > > > > really should only be done between encodeBegin() and encodeEnd(). So
> > > > > implementing this optimisation is a little tricky - but not impossible
> > > > > I'm sure.
> > > > >
> > > > > Regards,
> > > > >
> > > > > Simon
> > > > >
> > > > > Andrew Robinson wrote:
> > > > > > At the very least rendered is called during encodeBegin,
> > > > > > encodeChildren, and encodeEnd.
> > > > > >
> > > > > > On 5/8/07, Wesley Hales < wesleyhales@gmail.com> wrote:
> > > > > >> Hello - Why do we continually call isRendered after encodeBegin()?
> > > > > >> Once the
> > > > > >> begin tag is written out, it shouldn't matter what the body and end
> > > > > >> rendered
> > > > > >> states are.
> > > > > >>
> > > > > >> Facelets 1.1.11
> > > > > >>  Myfaces 1.1.5 & 1.2
> > > > > >>
> > > > > >> So if I have  <t:div rendered="#{ MyBean.alerts > 0}"...
> > > > > >> The #{MyBean.alerts method is called 5 times! and it is like this
> > for
> > > > > >> every
> > > > > >> EL eval on the page. I do know that EL can only bind to the
> > > > > >> FaceletsContext
> > > > > >> and no other scopes... So are there any other options than what I
> > have
> > > > > >> listed below?
> > > > > >>
> > > > > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > > > >> public boolean isRendered()
> > > > > >>      {
> > > > > >>            if(_rendered == null){
> > > > > >>
> > > > > >>            // our modification! Only compute the rendered value
> > once, and
> > > > > >> cache for the rest of the lifecycle.
> > > > > >>            Boolean rend = getExpressionValue("rendered", _rendered,
> > > > > >> DEFAULT_RENDERED);
> > > > > >>            _rendered = rend.booleanValue();
> > > > > >>            }
> > > > > >>          return _rendered;
> > > > > >>      }
> > > > > >> This didn't work :( - Something happend to A4J and we had no ideas
> > > > > >> what the
> > > > > >> implication would be on all components.
> > > > > >>
> > > > > >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> > page
> > > > > >> scoped variable, then have the variable evaluated in the rendered
> > > > > >> attribute.
> > > > > >> This didn't work either because it is on FacesContext.
> > > > > >>
> > > > > >> So this may just be me not fully understanding  what JSF does
> > behind the
> > > > > >> scenes of component rendering, or some people say that  the spec is
> > > > > >> screwed
> > > > > >> up when it comes to this. I'm sure some of the pros can help me out
> > > > > >> here :).
> > > > > >>
> > > > > >> Thx,
> > > > > >> Wesley Hales
> > > > >
> > > > >
> > > >
> > >
> > >
> >
> >
>

Re: Multiple calls on isRendered - Performance issue

Posted by Andrew Robinson <an...@gmail.com>.
You may want to submit a comment for the JSF specification on changing
this behavior.

On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> So the architect I am working with (Chris Kulinski) came up with the
> following patch to 1.1.5...
>
> Index: src/main/java/javax/faces/component/UIComponent.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIComponent.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIComponent.java
> (working copy)
> @@ -59,6 +59,8 @@
>
>      public abstract boolean isRendered();
>
> +    public abstract boolean isRenderedCached();
> +
>      public abstract void setRendered(boolean rendered);
>
>      public abstract java.lang.String getRendererType();
> Index: src/main/java/javax/faces/component/UIMessages.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIMessages.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIMessages.java
> (working copy)
> @@ -28,7 +28,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIMessages
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      //------------------ GENERATED CODE BEGIN (do not modify!)
> --------------------
>
> Index: src/main/java/javax/faces/component/UIData.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIData.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIData.java
> (working copy)
> @@ -126,7 +126,7 @@
>   * @author Manfred Geiler (latest modification by $Author$)
>   * @version $Revision$ $Date$
>   */
> -public class UIData extends UIComponentBase implements NamingContainer
> +public class UIData extends UIComponentBaseCached implements
> NamingContainer
>  {
>      private static final int STATE_SIZE = 5;
>      private static final int SUPER_STATE_INDEX = 0;
> @@ -577,7 +577,7 @@
>      {
>          if (context == null)
>              throw new NullPointerException("context");
> -        if (!isRendered())
> +        if (!isRenderedCached())
>              return;
>          setRowIndex(-1);
>          processFacets(context, PROCESS_DECODES);
> @@ -599,7 +599,7 @@
>      {
>          if (context == null)
>              throw new NullPointerException("context");
> -        if (!isRendered())
> +        if (!isRenderedCached())
>              return;
>          setRowIndex(-1);
>          processFacets(context, PROCESS_VALIDATORS);
> @@ -618,7 +618,7 @@
>      {
>          if (context == null)
>              throw new NullPointerException("context");
> -        if (!isRendered())
> +        if (!isRenderedCached())
>              return;
>          setRowIndex(-1);
>          processFacets(context, PROCESS_UPDATES);
> @@ -656,7 +656,7 @@
>              UIComponent child = (UIComponent) childIter.next();
>              if (child instanceof UIColumn)
>               {
> -                if (!child.isRendered())
> +                if (!child.isRenderedCached())
>                  {
>                      //Column is not visible
>                      continue;
> @@ -705,7 +705,7 @@
>                  UIComponent child = (UIComponent) it.next();
>                  if (child instanceof UIColumn)
>                  {
> -                    if (!child.isRendered())
> +                    if (!child.isRenderedCached())
>                      {
>                          //Column is not visible
>                          continue;
> Index: src/main/java/javax/faces/component/UIParameter.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIParameter.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIParameter.java
> (working copy)
> @@ -28,7 +28,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIParameter
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      //------------------ GENERATED CODE BEGIN (do not modify!)
> --------------------
>
> Index: src/main/java/javax/faces/component/UIMessage.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIMessage.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIMessage.java
> (working copy)
> @@ -30,7 +30,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIMessage
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      //------------------ GENERATED CODE BEGIN (do not modify!)
> --------------------
>
> Index: src/main/java/javax/faces/component/UIForm.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIForm.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIForm.java
> (working copy)
> @@ -28,7 +28,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIForm
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>          implements NamingContainer
>  {
>      //private static final Log log = LogFactory.getLog(UIForm.class);
> Index: src/main/java/javax/faces/component/UIGraphic.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIGraphic.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIGraphic.java
> (working copy)
> @@ -28,7 +28,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIGraphic
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      private static final String URL_PROPERTY = "url";
>      private static final String VALUE_PROPERTY = "value";
> Index: src/main/java/javax/faces/component/UICommand.java
> ===================================================================
> --- src/main/java/javax/faces/component/UICommand.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UICommand.java
> (working copy)
> @@ -31,7 +31,7 @@
>   * @version $Revision$ $Date$
>   */
>   public class UICommand
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>          implements ActionSource
>  {
>      private MethodBinding _action = null;
> Index: src/main/java/javax/faces/component/UIViewRoot.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIViewRoot.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIViewRoot.java
> (working copy)
> @@ -38,7 +38,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIViewRoot
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      public static final String UNIQUE_ID_PREFIX = "_id";
>
> Index: src/main/java/javax/faces/component/UIColumn.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIColumn.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIColumn.java
> (working copy)
> @@ -27,7 +27,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIColumn
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      private static final String FOOTER_FACET_NAME = "footer";
>      private static final String HEADER_FACET_NAME = "header";
> Index:
> src/main/java/javax/faces/component/UIComponentBase.java
> ===================================================================
> ---
> src/main/java/javax/faces/component/UIComponentBase.java
>    (revision 536301)
> +++
> src/main/java/javax/faces/component/UIComponentBase.java
>    (working copy)
> @@ -508,7 +508,7 @@
>              throws IOException
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -        if (!isRendered()) return;
> +        if (!isRenderedCached()) return;
>          Renderer renderer = getRenderer(context);
>          if (renderer != null)
>          {
> @@ -520,7 +520,7 @@
>              throws IOException
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -        if (!isRendered()) return;
> +        if (!isRenderedCached()) return;
>          Renderer renderer = getRenderer(context);
>          if (renderer != null)
>          {
> @@ -532,7 +532,7 @@
>              throws IOException
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -        if (!isRendered()) return;
> +        if (!isRenderedCached()) return;
>          Renderer renderer = getRenderer(context);
>          if (renderer != null)
>          {
> @@ -598,7 +598,7 @@
>      public void processDecodes(FacesContext context)
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -                if (!isRendered()) return;
> +                if (!isRenderedCached()) return;
>          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
>          {
>              UIComponent childOrFacet = (UIComponent)it.next();
> @@ -619,7 +619,7 @@
>      public void processValidators(FacesContext context)
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -        if (!isRendered()) return;
> +        if (!isRenderedCached()) return;
>
>          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
>          {
> @@ -640,7 +640,7 @@
>      public void processUpdates(FacesContext context)
>      {
>          if (context == null) throw new
> NullPointerException("context");
> -        if (!isRendered()) return;
> +        if (!isRenderedCached()) return;
>
>          for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
>          {
> @@ -1063,6 +1063,7 @@
>
>      private Boolean _rendered = null;
>      private String _rendererType = null;
> +    private Boolean _renderedCached = null;
>
>
>
> @@ -1072,11 +1073,29 @@
>      }
>
>      public boolean isRendered()
> +    {
> +        if (_rendered != null) return _rendered.booleanValue();
> +        ValueBinding vb = getValueBinding("rendered");
> +        // AUTOTRADER: Cache the rendered value so its not computed
> multiple times.
> +        _renderedCached = vb != null ?
> (Boolean)vb.getValue(getFacesContext()) : null;
> +        return _renderedCached != null ? _renderedCached.booleanValue() :
> DEFAULT_RENDERED;
> +    }
> +
> +    public boolean isRenderedCached()
>      {
>          if (_rendered != null) return _rendered.booleanValue();
> +
> +        // AUTOTRADER: Cache the rendered value so its not computed
> multiple times.
> +        if (_renderedCached != null) {
> +            //System.out.println("using CACHED value for:"+getId()+"
> "+this);
> +            return _renderedCached.booleanValue();
> +        }
> +
>          ValueBinding vb = getValueBinding("rendered");
> -        Boolean v = vb != null ?
> (Boolean)vb.getValue(getFacesContext()) : null;
> -        return v != null ? v.booleanValue() : DEFAULT_RENDERED;
> +        // AUTOTRADER: Cache the rendered value so its not computed
> multiple times.
> +        _renderedCached = vb != null ?
> (Boolean)vb.getValue(getFacesContext()) : null;
> +        //System.out.println("Computing NO CACHE value for:"+getId()+"
> "+this);
> +        return _renderedCached != null ? _renderedCached.booleanValue() :
> DEFAULT_RENDERED;
>      }
>
>      public void setRendererType(String rendererType)
> Index: src/main/java/javax/faces/component/UIPanel.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIPanel.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIPanel.java
> (working copy)
> @@ -27,7 +27,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIPanel
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>  {
>      //------------------ GENERATED CODE BEGIN (do not modify!)
> --------------------
>
> Index: src/main/java/javax/faces/component/UIOutput.java
> ===================================================================
> --- src/main/java/javax/faces/component/UIOutput.java
> (revision 536301)
> +++ src/main/java/javax/faces/component/UIOutput.java
> (working copy)
> @@ -29,7 +29,7 @@
>   * @version $Revision$ $Date$
>   */
>  public class UIOutput
> -        extends UIComponentBase
> +        extends UIComponentBaseCached
>          implements ValueHolder
>  {
>      public Object getLocalValue()
> ---------------------------------------------------------------------------------
>
> and here is the UIComponentBaseCached class:
>
> package javax.faces.component;
>
> public abstract class UIComponentBaseCached extends UIComponentBase {
>
>     public boolean isRendered()
>     {
>         return isRenderedCached();
>     }
> }
>
>
> So far so good, I will post the results if anything stops working.
>
> Wesley
>
>
>
>
>  On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
> > I am trying to address this at a framework level (i.e. I'm not rewriting
> the renderer for each component that calls an EL method)
> >
> >
> >
> > On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
> > > Technically, rendered is supposed to be:
> > > - Constant across
> encodeBegin()/encodeChildren()/encodeEnd()
> > > - Constant across processDecodes()/processValidators()/
> > >    processUpdateModel().
> > >
> > > Unfortunately, the latter doesn't help - since a component inside
> > > a table would have processDecodes() called repeatedly,
> > > then processValidators() repeatedly, etc. - and "rendered"
> > > could be different from one row to the next.
> > >
> > > But the former should be fine - if you always fetch and
> > > store the value in encodeBegin() (whether or not encodeBegin()
> > > has previously been called), then use that in encodeChildren()
> > > and encodeEnd(), you should be fine.
> > >
> > > -- Adam
> > >
> > >
> > > On 5/8/07, Simon Kitching < simon.kitching@rhe.co.nz> wrote:
> > > > Andrew, are you just stating what currently happens or are you saying
> > > > that there is a *reason* for evaluating "rendered" in encodeBegin,
> > > > encodeChildren and encodeEnd?
> > > >
> > > > I can't initially see any reason why it would need to be evaluated
> more
> > > > than once.
> > > >
> > > > UIComponentBase does indeed call isRendered in encodeBegin,
> > > > encodeChildren and encodeEnd. It also implements isRendered as an
> > > > evaluation of the EL expression (myfaces 1.1.3 implementation).
> > > >
> > > > But As Wesley asks, why would it ever make sense for rendered to be
> true
> > > > in encodeBegin, but false in encodeEnd? I cannot see any way that
> would
> > > > be useful, so why not just compute it once then cache it somewhere for
> > > > the rest of that render cycle (eg in a "transient" member of the
> > > > component)? This would be a significant performance boost..
> > > >
> > > > Wesley, your proposed modification which stores the rendered state
> into
> > > > _rendered is not good because setting _rendered will permanently
> > > > override the rendered EL expression, not just for the current render
> > > > cycle but for the lifetime of that component. What is needed is to
> > > > figure out when the first call to isRendered is done *during the
> render
> > > > cycle* and then cache that until rendering finishes. Note that
> > > > isRendered is also called during postback processing, and it's
> perfectly
> > > > reasonable to change this value between postback and render so caching
> > > > really should only be done between encodeBegin() and encodeEnd(). So
> > > > implementing this optimisation is a little tricky - but not impossible
> > > > I'm sure.
> > > >
> > > > Regards,
> > > >
> > > > Simon
> > > >
> > > > Andrew Robinson wrote:
> > > > > At the very least rendered is called during encodeBegin,
> > > > > encodeChildren, and encodeEnd.
> > > > >
> > > > > On 5/8/07, Wesley Hales < wesleyhales@gmail.com> wrote:
> > > > >> Hello - Why do we continually call isRendered after encodeBegin()?
> > > > >> Once the
> > > > >> begin tag is written out, it shouldn't matter what the body and end
> > > > >> rendered
> > > > >> states are.
> > > > >>
> > > > >> Facelets 1.1.11
> > > > >>  Myfaces 1.1.5 & 1.2
> > > > >>
> > > > >> So if I have  <t:div rendered="#{ MyBean.alerts > 0}"...
> > > > >> The #{MyBean.alerts method is called 5 times! and it is like this
> for
> > > > >> every
> > > > >> EL eval on the page. I do know that EL can only bind to the
> > > > >> FaceletsContext
> > > > >> and no other scopes... So are there any other options than what I
> have
> > > > >> listed below?
> > > > >>
> > > > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > > >> public boolean isRendered()
> > > > >>      {
> > > > >>            if(_rendered == null){
> > > > >>
> > > > >>            // our modification! Only compute the rendered value
> once, and
> > > > >> cache for the rest of the lifecycle.
> > > > >>            Boolean rend = getExpressionValue("rendered", _rendered,
> > > > >> DEFAULT_RENDERED);
> > > > >>            _rendered = rend.booleanValue();
> > > > >>            }
> > > > >>          return _rendered;
> > > > >>      }
> > > > >> This didn't work :( - Something happend to A4J and we had no ideas
> > > > >> what the
> > > > >> implication would be on all components.
> > > > >>
> > > > >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> page
> > > > >> scoped variable, then have the variable evaluated in the rendered
> > > > >> attribute.
> > > > >> This didn't work either because it is on FacesContext.
> > > > >>
> > > > >> So this may just be me not fully understanding  what JSF does
> behind the
> > > > >> scenes of component rendering, or some people say that  the spec is
> > > > >> screwed
> > > > >> up when it comes to this. I'm sure some of the pros can help me out
> > > > >> here :).
> > > > >>
> > > > >> Thx,
> > > > >> Wesley Hales
> > > >
> > > >
> > >
> >
> >
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Wesley Hales <we...@gmail.com>.
So the architect I am working with (Chris Kulinski) came up with the
following patch to 1.1.5...

Index: src/main/java/javax/faces/component/UIComponent.java
===================================================================
--- src/main/java/javax/faces/component/UIComponent.java    (revision
536301)
+++ src/main/java/javax/faces/component/UIComponent.java    (working copy)
@@ -59,6 +59,8 @@

     public abstract boolean isRendered();

+    public abstract boolean isRenderedCached();
+
     public abstract void setRendered(boolean rendered);

     public abstract java.lang.String getRendererType();
Index: src/main/java/javax/faces/component/UIMessages.java
===================================================================
--- src/main/java/javax/faces/component/UIMessages.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIMessages.java    (working copy)
@@ -28,7 +28,7 @@
  * @version $Revision$ $Date$
  */
 public class UIMessages
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     //------------------ GENERATED CODE BEGIN (do not modify!)
--------------------

Index: src/main/java/javax/faces/component/UIData.java
===================================================================
--- src/main/java/javax/faces/component/UIData.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIData.java    (working copy)
@@ -126,7 +126,7 @@
  * @author Manfred Geiler (latest modification by $Author$)
  * @version $Revision$ $Date$
  */
-public class UIData extends UIComponentBase implements NamingContainer
+public class UIData extends UIComponentBaseCached implements
NamingContainer
 {
     private static final int STATE_SIZE = 5;
     private static final int SUPER_STATE_INDEX = 0;
@@ -577,7 +577,7 @@
     {
         if (context == null)
             throw new NullPointerException("context");
-        if (!isRendered())
+        if (!isRenderedCached())
             return;
         setRowIndex(-1);
         processFacets(context, PROCESS_DECODES);
@@ -599,7 +599,7 @@
     {
         if (context == null)
             throw new NullPointerException("context");
-        if (!isRendered())
+        if (!isRenderedCached())
             return;
         setRowIndex(-1);
         processFacets(context, PROCESS_VALIDATORS);
@@ -618,7 +618,7 @@
     {
         if (context == null)
             throw new NullPointerException("context");
-        if (!isRendered())
+        if (!isRenderedCached())
             return;
         setRowIndex(-1);
         processFacets(context, PROCESS_UPDATES);
@@ -656,7 +656,7 @@
             UIComponent child = (UIComponent) childIter.next();
             if (child instanceof UIColumn)
             {
-                if (!child.isRendered())
+                if (!child.isRenderedCached())
                 {
                     //Column is not visible
                     continue;
@@ -705,7 +705,7 @@
                 UIComponent child = (UIComponent) it.next();
                 if (child instanceof UIColumn)
                 {
-                    if (!child.isRendered())
+                    if (!child.isRenderedCached())
                     {
                         //Column is not visible
                         continue;
Index: src/main/java/javax/faces/component/UIParameter.java
===================================================================
--- src/main/java/javax/faces/component/UIParameter.java    (revision
536301)
+++ src/main/java/javax/faces/component/UIParameter.java    (working copy)
@@ -28,7 +28,7 @@
  * @version $Revision$ $Date$
  */
 public class UIParameter
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     //------------------ GENERATED CODE BEGIN (do not modify!)
--------------------

Index: src/main/java/javax/faces/component/UIMessage.java
===================================================================
--- src/main/java/javax/faces/component/UIMessage.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIMessage.java    (working copy)
@@ -30,7 +30,7 @@
  * @version $Revision$ $Date$
  */
 public class UIMessage
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     //------------------ GENERATED CODE BEGIN (do not modify!)
--------------------

Index: src/main/java/javax/faces/component/UIForm.java
===================================================================
--- src/main/java/javax/faces/component/UIForm.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIForm.java    (working copy)
@@ -28,7 +28,7 @@
  * @version $Revision$ $Date$
  */
 public class UIForm
-        extends UIComponentBase
+        extends UIComponentBaseCached
         implements NamingContainer
 {
     //private static final Log log = LogFactory.getLog(UIForm.class);
Index: src/main/java/javax/faces/component/UIGraphic.java
===================================================================
--- src/main/java/javax/faces/component/UIGraphic.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIGraphic.java    (working copy)
@@ -28,7 +28,7 @@
  * @version $Revision$ $Date$
  */
 public class UIGraphic
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     private static final String URL_PROPERTY = "url";
     private static final String VALUE_PROPERTY = "value";
Index: src/main/java/javax/faces/component/UICommand.java
===================================================================
--- src/main/java/javax/faces/component/UICommand.java    (revision 536301)
+++ src/main/java/javax/faces/component/UICommand.java    (working copy)
@@ -31,7 +31,7 @@
  * @version $Revision$ $Date$
  */
 public class UICommand
-        extends UIComponentBase
+        extends UIComponentBaseCached
         implements ActionSource
 {
     private MethodBinding _action = null;
Index: src/main/java/javax/faces/component/UIViewRoot.java
===================================================================
--- src/main/java/javax/faces/component/UIViewRoot.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIViewRoot.java    (working copy)
@@ -38,7 +38,7 @@
  * @version $Revision$ $Date$
  */
 public class UIViewRoot
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     public static final String UNIQUE_ID_PREFIX = "_id";

Index: src/main/java/javax/faces/component/UIColumn.java
===================================================================
--- src/main/java/javax/faces/component/UIColumn.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIColumn.java    (working copy)
@@ -27,7 +27,7 @@
  * @version $Revision$ $Date$
  */
 public class UIColumn
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     private static final String FOOTER_FACET_NAME = "footer";
     private static final String HEADER_FACET_NAME = "header";
Index: src/main/java/javax/faces/component/UIComponentBase.java
===================================================================
--- src/main/java/javax/faces/component/UIComponentBase.java    (revision
536301)
+++ src/main/java/javax/faces/component/UIComponentBase.java    (working
copy)
@@ -508,7 +508,7 @@
             throws IOException
     {
         if (context == null) throw new NullPointerException("context");
-        if (!isRendered()) return;
+        if (!isRenderedCached()) return;
         Renderer renderer = getRenderer(context);
         if (renderer != null)
         {
@@ -520,7 +520,7 @@
             throws IOException
     {
         if (context == null) throw new NullPointerException("context");
-        if (!isRendered()) return;
+        if (!isRenderedCached()) return;
         Renderer renderer = getRenderer(context);
         if (renderer != null)
         {
@@ -532,7 +532,7 @@
             throws IOException
     {
         if (context == null) throw new NullPointerException("context");
-        if (!isRendered()) return;
+        if (!isRenderedCached()) return;
         Renderer renderer = getRenderer(context);
         if (renderer != null)
         {
@@ -598,7 +598,7 @@
     public void processDecodes(FacesContext context)
     {
         if (context == null) throw new NullPointerException("context");
-                if (!isRendered()) return;
+                if (!isRenderedCached()) return;
         for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
         {
             UIComponent childOrFacet = (UIComponent)it.next();
@@ -619,7 +619,7 @@
     public void processValidators(FacesContext context)
     {
         if (context == null) throw new NullPointerException("context");
-        if (!isRendered()) return;
+        if (!isRenderedCached()) return;

         for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
         {
@@ -640,7 +640,7 @@
     public void processUpdates(FacesContext context)
     {
         if (context == null) throw new NullPointerException("context");
-        if (!isRendered()) return;
+        if (!isRenderedCached()) return;

         for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
         {
@@ -1063,6 +1063,7 @@

     private Boolean _rendered = null;
     private String _rendererType = null;
+    private Boolean _renderedCached = null;



@@ -1072,11 +1073,29 @@
     }

     public boolean isRendered()
+    {
+        if (_rendered != null) return _rendered.booleanValue();
+        ValueBinding vb = getValueBinding("rendered");
+        // AUTOTRADER: Cache the rendered value so its not computed
multiple times.
+        _renderedCached = vb != null ?
(Boolean)vb.getValue(getFacesContext()) : null;
+        return _renderedCached != null ? _renderedCached.booleanValue() :
DEFAULT_RENDERED;
+    }
+
+    public boolean isRenderedCached()
     {
         if (_rendered != null) return _rendered.booleanValue();
+
+        // AUTOTRADER: Cache the rendered value so its not computed
multiple times.
+        if (_renderedCached != null) {
+            //System.out.println("using CACHED value for:"+getId()+"
"+this);
+            return _renderedCached.booleanValue();
+        }
+
         ValueBinding vb = getValueBinding("rendered");
-        Boolean v = vb != null ? (Boolean)vb.getValue(getFacesContext()) :
null;
-        return v != null ? v.booleanValue() : DEFAULT_RENDERED;
+        // AUTOTRADER: Cache the rendered value so its not computed
multiple times.
+        _renderedCached = vb != null ?
(Boolean)vb.getValue(getFacesContext()) : null;
+        //System.out.println("Computing NO CACHE value for:"+getId()+"
"+this);
+        return _renderedCached != null ? _renderedCached.booleanValue() :
DEFAULT_RENDERED;
     }

     public void setRendererType(String rendererType)
Index: src/main/java/javax/faces/component/UIPanel.java
===================================================================
--- src/main/java/javax/faces/component/UIPanel.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIPanel.java    (working copy)
@@ -27,7 +27,7 @@
  * @version $Revision$ $Date$
  */
 public class UIPanel
-        extends UIComponentBase
+        extends UIComponentBaseCached
 {
     //------------------ GENERATED CODE BEGIN (do not modify!)
--------------------

Index: src/main/java/javax/faces/component/UIOutput.java
===================================================================
--- src/main/java/javax/faces/component/UIOutput.java    (revision 536301)
+++ src/main/java/javax/faces/component/UIOutput.java    (working copy)
@@ -29,7 +29,7 @@
  * @version $Revision$ $Date$
  */
 public class UIOutput
-        extends UIComponentBase
+        extends UIComponentBaseCached
         implements ValueHolder
 {
     public Object getLocalValue()
---------------------------------------------------------------------------------

and here is the UIComponentBaseCached class:

package javax.faces.component;

public abstract class UIComponentBaseCached extends UIComponentBase {

    public boolean isRendered()
    {
        return isRenderedCached();
    }
}


So far so good, I will post the results if anything stops working.

Wesley



On 5/9/07, Wesley Hales <we...@gmail.com> wrote:
>
> I am trying to address this at a framework level (i.e. I'm not rewriting
> the renderer for each component that calls an EL method)
>
> On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
> >
> > Technically, rendered is supposed to be:
> > - Constant across encodeBegin()/encodeChildren()/encodeEnd()
> > - Constant across processDecodes()/processValidators()/
> >    processUpdateModel().
> >
> > Unfortunately, the latter doesn't help - since a component inside
> > a table would have processDecodes() called repeatedly,
> > then processValidators() repeatedly, etc. - and "rendered"
> > could be different from one row to the next.
> >
> > But the former should be fine - if you always fetch and
> > store the value in encodeBegin() (whether or not encodeBegin()
> > has previously been called), then use that in encodeChildren()
> > and encodeEnd(), you should be fine.
> >
> > -- Adam
> >
> >
> > On 5/8/07, Simon Kitching < simon.kitching@rhe.co.nz> wrote:
> > > Andrew, are you just stating what currently happens or are you saying
> > > that there is a *reason* for evaluating "rendered" in encodeBegin,
> > > encodeChildren and encodeEnd?
> > >
> > > I can't initially see any reason why it would need to be evaluated
> > more
> > > than once.
> > >
> > > UIComponentBase does indeed call isRendered in encodeBegin,
> > > encodeChildren and encodeEnd. It also implements isRendered as an
> > > evaluation of the EL expression (myfaces 1.1.3 implementation).
> > >
> > > But As Wesley asks, why would it ever make sense for rendered to be
> > true
> > > in encodeBegin, but false in encodeEnd? I cannot see any way that
> > would
> > > be useful, so why not just compute it once then cache it somewhere for
> > > the rest of that render cycle (eg in a "transient" member of the
> > > component)? This would be a significant performance boost..
> > >
> > > Wesley, your proposed modification which stores the rendered state
> > into
> > > _rendered is not good because setting _rendered will permanently
> > > override the rendered EL expression, not just for the current render
> > > cycle but for the lifetime of that component. What is needed is to
> > > figure out when the first call to isRendered is done *during the
> > render
> > > cycle* and then cache that until rendering finishes. Note that
> > > isRendered is also called during postback processing, and it's
> > perfectly
> > > reasonable to change this value between postback and render so caching
> >
> > > really should only be done between encodeBegin() and encodeEnd(). So
> > > implementing this optimisation is a little tricky - but not impossible
> > > I'm sure.
> > >
> > > Regards,
> > >
> > > Simon
> > >
> > > Andrew Robinson wrote:
> > > > At the very least rendered is called during encodeBegin,
> > > > encodeChildren, and encodeEnd.
> > > >
> > > > On 5/8/07, Wesley Hales < wesleyhales@gmail.com> wrote:
> > > >> Hello - Why do we continually call isRendered after encodeBegin()?
> > > >> Once the
> > > >> begin tag is written out, it shouldn't matter what the body and end
> >
> > > >> rendered
> > > >> states are.
> > > >>
> > > >> Facelets 1.1.11
> > > >>  Myfaces 1.1.5 & 1.2
> > > >>
> > > >> So if I have  <t:div rendered="#{ MyBean.alerts > 0}"...
> > > >> The #{MyBean.alerts method is called 5 times! and it is like this
> > for
> > > >> every
> > > >> EL eval on the page. I do know that EL can only bind to the
> > > >> FaceletsContext
> > > >> and no other scopes... So are there any other options than what I
> > have
> > > >> listed below?
> > > >>
> > > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > > >> public boolean isRendered()
> > > >>      {
> > > >>            if(_rendered == null){
> > > >>
> > > >>            // our modification! Only compute the rendered value
> > once, and
> > > >> cache for the rest of the lifecycle.
> > > >>            Boolean rend = getExpressionValue("rendered", _rendered,
> > > >> DEFAULT_RENDERED);
> > > >>            _rendered = rend.booleanValue();
> > > >>            }
> > > >>          return _rendered;
> > > >>      }
> > > >> This didn't work :( - Something happend to A4J and we had no ideas
> > > >> what the
> > > >> implication would be on all components.
> > > >>
> > > >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> > page
> > > >> scoped variable, then have the variable evaluated in the rendered
> > > >> attribute.
> > > >> This didn't work either because it is on FacesContext.
> > > >>
> > > >> So this may just be me not fully understanding  what JSF does
> > behind the
> > > >> scenes of component rendering, or some people say that  the spec is
> >
> > > >> screwed
> > > >> up when it comes to this. I'm sure some of the pros can help me out
> > > >> here :).
> > > >>
> > > >> Thx,
> > > >> Wesley Hales
> > >
> > >
> >
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Wesley Hales <we...@gmail.com>.
I am trying to address this at a framework level (i.e. I'm not rewriting the
renderer for each component that calls an EL method)

On 5/9/07, Adam Winer <aw...@gmail.com> wrote:
>
> Technically, rendered is supposed to be:
> - Constant across encodeBegin()/encodeChildren()/encodeEnd()
> - Constant across processDecodes()/processValidators()/
>    processUpdateModel().
>
> Unfortunately, the latter doesn't help - since a component inside
> a table would have processDecodes() called repeatedly,
> then processValidators() repeatedly, etc. - and "rendered"
> could be different from one row to the next.
>
> But the former should be fine - if you always fetch and
> store the value in encodeBegin() (whether or not encodeBegin()
> has previously been called), then use that in encodeChildren()
> and encodeEnd(), you should be fine.
>
> -- Adam
>
>
> On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
> > Andrew, are you just stating what currently happens or are you saying
> > that there is a *reason* for evaluating "rendered" in encodeBegin,
> > encodeChildren and encodeEnd?
> >
> > I can't initially see any reason why it would need to be evaluated more
> > than once.
> >
> > UIComponentBase does indeed call isRendered in encodeBegin,
> > encodeChildren and encodeEnd. It also implements isRendered as an
> > evaluation of the EL expression (myfaces 1.1.3 implementation).
> >
> > But As Wesley asks, why would it ever make sense for rendered to be true
> > in encodeBegin, but false in encodeEnd? I cannot see any way that would
> > be useful, so why not just compute it once then cache it somewhere for
> > the rest of that render cycle (eg in a "transient" member of the
> > component)? This would be a significant performance boost..
> >
> > Wesley, your proposed modification which stores the rendered state into
> > _rendered is not good because setting _rendered will permanently
> > override the rendered EL expression, not just for the current render
> > cycle but for the lifetime of that component. What is needed is to
> > figure out when the first call to isRendered is done *during the render
> > cycle* and then cache that until rendering finishes. Note that
> > isRendered is also called during postback processing, and it's perfectly
> > reasonable to change this value between postback and render so caching
> > really should only be done between encodeBegin() and encodeEnd(). So
> > implementing this optimisation is a little tricky - but not impossible
> > I'm sure.
> >
> > Regards,
> >
> > Simon
> >
> > Andrew Robinson wrote:
> > > At the very least rendered is called during encodeBegin,
> > > encodeChildren, and encodeEnd.
> > >
> > > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> > >> Hello - Why do we continually call isRendered after encodeBegin()?
> > >> Once the
> > >> begin tag is written out, it shouldn't matter what the body and end
> > >> rendered
> > >> states are.
> > >>
> > >> Facelets 1.1.11
> > >>  Myfaces 1.1.5 & 1.2
> > >>
> > >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> > >> The #{MyBean.alerts method is called 5 times! and it is like this for
> > >> every
> > >> EL eval on the page. I do know that EL can only bind to the
> > >> FaceletsContext
> > >> and no other scopes... So are there any other options than what I
> have
> > >> listed below?
> > >>
> > >> 1. Tried to modify MyFaces src in UIComponentBase:
> > >> public boolean isRendered()
> > >>      {
> > >>            if(_rendered == null){
> > >>
> > >>            // our modification! Only compute the rendered value once,
> and
> > >> cache for the rest of the lifecycle.
> > >>            Boolean rend = getExpressionValue("rendered", _rendered,
> > >> DEFAULT_RENDERED);
> > >>            _rendered = rend.booleanValue();
> > >>            }
> > >>          return _rendered;
> > >>      }
> > >> This didn't work :( - Something happend to A4J and we had no ideas
> > >> what the
> > >> implication would be on all components.
> > >>
> > >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a
> page
> > >> scoped variable, then have the variable evaluated in the rendered
> > >> attribute.
> > >> This didn't work either because it is on FacesContext.
> > >>
> > >> So this may just be me not fully understanding  what JSF does behind
> the
> > >> scenes of component rendering, or some people say that  the spec is
> > >> screwed
> > >> up when it comes to this. I'm sure some of the pros can help me out
> > >> here :).
> > >>
> > >> Thx,
> > >> Wesley Hales
> >
> >
>

Re: Multiple calls on isRendered - Performance issue

Posted by Adam Winer <aw...@gmail.com>.
Technically, rendered is supposed to be:
 - Constant across encodeBegin()/encodeChildren()/encodeEnd()
 - Constant across processDecodes()/processValidators()/
   processUpdateModel().

Unfortunately, the latter doesn't help - since a component inside
a table would have processDecodes() called repeatedly,
then processValidators() repeatedly, etc. - and "rendered"
could be different from one row to the next.

But the former should be fine - if you always fetch and
store the value in encodeBegin() (whether or not encodeBegin()
has previously been called), then use that in encodeChildren()
and encodeEnd(), you should be fine.

-- Adam


On 5/8/07, Simon Kitching <si...@rhe.co.nz> wrote:
> Andrew, are you just stating what currently happens or are you saying
> that there is a *reason* for evaluating "rendered" in encodeBegin,
> encodeChildren and encodeEnd?
>
> I can't initially see any reason why it would need to be evaluated more
> than once.
>
> UIComponentBase does indeed call isRendered in encodeBegin,
> encodeChildren and encodeEnd. It also implements isRendered as an
> evaluation of the EL expression (myfaces 1.1.3 implementation).
>
> But As Wesley asks, why would it ever make sense for rendered to be true
> in encodeBegin, but false in encodeEnd? I cannot see any way that would
> be useful, so why not just compute it once then cache it somewhere for
> the rest of that render cycle (eg in a "transient" member of the
> component)? This would be a significant performance boost..
>
> Wesley, your proposed modification which stores the rendered state into
> _rendered is not good because setting _rendered will permanently
> override the rendered EL expression, not just for the current render
> cycle but for the lifetime of that component. What is needed is to
> figure out when the first call to isRendered is done *during the render
> cycle* and then cache that until rendering finishes. Note that
> isRendered is also called during postback processing, and it's perfectly
> reasonable to change this value between postback and render so caching
> really should only be done between encodeBegin() and encodeEnd(). So
> implementing this optimisation is a little tricky - but not impossible
> I'm sure.
>
> Regards,
>
> Simon
>
> Andrew Robinson wrote:
> > At the very least rendered is called during encodeBegin,
> > encodeChildren, and encodeEnd.
> >
> > On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> >> Hello - Why do we continually call isRendered after encodeBegin()?
> >> Once the
> >> begin tag is written out, it shouldn't matter what the body and end
> >> rendered
> >> states are.
> >>
> >> Facelets 1.1.11
> >>  Myfaces 1.1.5 & 1.2
> >>
> >> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> >> The #{MyBean.alerts method is called 5 times! and it is like this for
> >> every
> >> EL eval on the page. I do know that EL can only bind to the
> >> FaceletsContext
> >> and no other scopes... So are there any other options than what I have
> >> listed below?
> >>
> >> 1. Tried to modify MyFaces src in UIComponentBase:
> >> public boolean isRendered()
> >>      {
> >>            if(_rendered == null){
> >>
> >>            // our modification! Only compute the rendered value once, and
> >> cache for the rest of the lifecycle.
> >>            Boolean rend = getExpressionValue("rendered", _rendered,
> >> DEFAULT_RENDERED);
> >>            _rendered = rend.booleanValue();
> >>            }
> >>          return _rendered;
> >>      }
> >> This didn't work :( - Something happend to A4J and we had no ideas
> >> what the
> >> implication would be on all components.
> >>
> >> 2. Tried using Facelets <ui:param and <c:set to store the EL in a page
> >> scoped variable, then have the variable evaluated in the rendered
> >> attribute.
> >> This didn't work either because it is on FacesContext.
> >>
> >> So this may just be me not fully understanding  what JSF does behind the
> >> scenes of component rendering, or some people say that  the spec is
> >> screwed
> >> up when it comes to this. I'm sure some of the pros can help me out
> >> here :).
> >>
> >> Thx,
> >> Wesley Hales
>
>

Re: Multiple calls on isRendered - Performance issue

Posted by Simon Kitching <si...@rhe.co.nz>.
Andrew, are you just stating what currently happens or are you saying 
that there is a *reason* for evaluating "rendered" in encodeBegin, 
encodeChildren and encodeEnd?

I can't initially see any reason why it would need to be evaluated more 
than once.

UIComponentBase does indeed call isRendered in encodeBegin, 
encodeChildren and encodeEnd. It also implements isRendered as an 
evaluation of the EL expression (myfaces 1.1.3 implementation).

But As Wesley asks, why would it ever make sense for rendered to be true 
in encodeBegin, but false in encodeEnd? I cannot see any way that would 
be useful, so why not just compute it once then cache it somewhere for 
the rest of that render cycle (eg in a "transient" member of the 
component)? This would be a significant performance boost..

Wesley, your proposed modification which stores the rendered state into 
_rendered is not good because setting _rendered will permanently 
override the rendered EL expression, not just for the current render 
cycle but for the lifetime of that component. What is needed is to 
figure out when the first call to isRendered is done *during the render 
cycle* and then cache that until rendering finishes. Note that 
isRendered is also called during postback processing, and it's perfectly 
reasonable to change this value between postback and render so caching 
really should only be done between encodeBegin() and encodeEnd(). So 
implementing this optimisation is a little tricky - but not impossible 
I'm sure.

Regards,

Simon

Andrew Robinson wrote:
> At the very least rendered is called during encodeBegin,
> encodeChildren, and encodeEnd.
> 
> On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
>> Hello - Why do we continually call isRendered after encodeBegin()? 
>> Once the
>> begin tag is written out, it shouldn't matter what the body and end 
>> rendered
>> states are.
>>
>> Facelets 1.1.11
>>  Myfaces 1.1.5 & 1.2
>>
>> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
>> The #{MyBean.alerts method is called 5 times! and it is like this for 
>> every
>> EL eval on the page. I do know that EL can only bind to the 
>> FaceletsContext
>> and no other scopes... So are there any other options than what I have
>> listed below?
>>
>> 1. Tried to modify MyFaces src in UIComponentBase:
>> public boolean isRendered()
>>      {
>>            if(_rendered == null){
>>
>>            // our modification! Only compute the rendered value once, and
>> cache for the rest of the lifecycle.
>>            Boolean rend = getExpressionValue("rendered", _rendered,
>> DEFAULT_RENDERED);
>>            _rendered = rend.booleanValue();
>>            }
>>          return _rendered;
>>      }
>> This didn't work :( - Something happend to A4J and we had no ideas 
>> what the
>> implication would be on all components.
>>
>> 2. Tried using Facelets <ui:param and <c:set to store the EL in a page
>> scoped variable, then have the variable evaluated in the rendered 
>> attribute.
>> This didn't work either because it is on FacesContext.
>>
>> So this may just be me not fully understanding  what JSF does behind the
>> scenes of component rendering, or some people say that  the spec is 
>> screwed
>> up when it comes to this. I'm sure some of the pros can help me out 
>> here :).
>>
>> Thx,
>> Wesley Hales


Re: Multiple calls on isRendered - Performance issue

Posted by Andrew Robinson <an...@gmail.com>.
At the very least rendered is called during encodeBegin,
encodeChildren, and encodeEnd.

On 5/8/07, Wesley Hales <we...@gmail.com> wrote:
> Hello - Why do we continually call isRendered after encodeBegin()? Once the
> begin tag is written out, it shouldn't matter what the body and end rendered
> states are.
>
> Facelets 1.1.11
>  Myfaces 1.1.5 & 1.2
>
> So if I have  <t:div rendered="#{MyBean.alerts > 0}"...
> The #{MyBean.alerts method is called 5 times! and it is like this for every
> EL eval on the page. I do know that EL can only bind to the FaceletsContext
> and no other scopes... So are there any other options than what I have
> listed below?
>
> 1. Tried to modify MyFaces src in UIComponentBase:
> public boolean isRendered()
>      {
>            if(_rendered == null){
>
>            // our modification! Only compute the rendered value once, and
> cache for the rest of the lifecycle.
>            Boolean rend = getExpressionValue("rendered", _rendered,
> DEFAULT_RENDERED);
>            _rendered = rend.booleanValue();
>            }
>          return _rendered;
>      }
> This didn't work :( - Something happend to A4J and we had no ideas what the
> implication would be on all components.
>
> 2. Tried using Facelets <ui:param and <c:set to store the EL in a page
> scoped variable, then have the variable evaluated in the rendered attribute.
> This didn't work either because it is on FacesContext.
>
> So this may just be me not fully understanding  what JSF does behind the
> scenes of component rendering, or some people say that  the spec is screwed
> up when it comes to this. I'm sure some of the pros can help me out here :).
>
> Thx,
> Wesley Hales