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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> 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 < [EMAIL PROTECTED]> 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 < [EMAIL PROTECTED]> 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
> > >
> > >
> >
>
>