2010/3/29 Ed Burns <edward.burns@oracle.com>
>>>>> On Sun, 28 Mar 2010 21:21:10 -0500, Leonardo Uribe <lu4242@gmail.com> said:

LU> The problem is why it is mandatory to set "javax.faces.Composite" as
LU> renderer type. The javadoc should say:

LU> "...If the renderer type is not set (return null), Call
LU> UIComponent.setRendererType(java.lang.String)<file:///D:/jdk-1_5_0-doc/jsf20/mojarra-2.0.3-SNAPSHOT/docs/javadocs/javax/faces/component/UIComponent.html#setRendererType%28java.lang.String%29>on
LU> the
LU> UIComponent instance, passing "javax.faces.Composite" as the argument...".
LU> In that case, a user can override the rendererType on the constructor and
LU> avoid this hack that works with the current spec:

I understand the problem you have uncovered.  Take a look at the
renderkit docs for javax.faces.NamingContainer/javax.faces.Composite.
There are specific requirements in there that depend on the composite
component metadata specification.

I thought it would be toooooooo subtle to allow the Renderer to be
customized beause this contract must also be followed in the custom
renderer case.

LU> Why override the default Renderer and use a custom one? Let's
LU> suppose the component proposed needs some custom code for converter,
LU> or for decode. The right place to put that kind of code is the
LU> Renderer class, not the component, but note it is possible to put
LU> that on the component class.

Yes I understand that the Renderer is the right place for such things
but the chosen programming model for customization of composite
components is to override the top level component.  Simple.  If we're
going to change that I need a more compelling reason than correctness.


The current behavior of javax.faces.NamingContainer/javax.faces.Composite renderer says that everything
inside the facet UIComponent.COMPOSITE_FACET_NAME should be rendered. But sometimes
the markup of the component changes according to its inner state. One simple example is
h:commandLink. If this component is disabled, it should be rendered a <span> instead use <a>.
Other example is tomahawk displayValueOnly property, that when is set to true, only the value
needs to be rendered.

Ok, if I have a composite component the first thought is use c:if tag, but remember that with
partial state saving enabled this tag is evaluated when the view is build, not when it is
rendered. Other alternative is use a component that allows to render one child at the time, and
it is on myfaces commons (mc:renderOne, old sandbox s:limitRendered). The third alternative is
use a custom renderer. The example I'm trying to do is this (all non relevant code has been removed:

    public void encodeEnd(FacesContext context, UIComponent component)
            throws IOException
    {
        UIComponent compositeFacet = (UIComponent) component
                .getFacet(UIComponent.COMPOSITE_FACET_NAME);
        CompositeInputHtml editor = (CompositeInputHtml) component;       
        if( HtmlRendererUtils.isDisplayValueOnly(editor) )
        {
            encodeDisplayValueOnly(context, editor);
        }
        else if ( useFallback(editor) )
        {
            encodeEndFallBackMode(context, editor);
        }
        else
        {
            if( ! isVisible(editor) ){
                encodeHidden(context, editor);
            }
            else if( ! hasAnotherPropertyThatPreventsRenderThisOneCorrectly( context ) )
            {
                compositeFacet.encodeAll(context);
            }
            else
            {
                encodeEndFallBackMode(context, editor);
            }
        }
    }

It is possible to think in other cases, like a composite component like this:

<composite:implementation>
<f:facet name="normal">
......some html markup......
</f:facet>
<f:facet name="disabled">
......some html markup......
</f:facet>
<f:facet name="special">
......some html markup......
</f:facet>
<composite:implementation>

And use a custom renderer to control when one or other facet should be rendered.

Note that in fact, with the hack on the component class on setRendererType, it is possible
to override the Renderer without problem, so for my particular problem I can live with it.
The question is if the spec should enforce the use of
javax.faces.NamingContainer/javax.faces.Composite renderer for composite components
or not.

Leonardo
 
Ed

--
| edward.burns@oracle.com  | office: 408 884 9519 OR x31640
| homepage:                | http://ridingthecrest.com/