[jsr-314-open] JSF 2.0/Facelets public APIs: ComponentHandler

Pete Muir pmuir at REDHAT.COM
Wed Mar 4 10:27:20 EST 2009


On 4 Mar 2009, at 04:29, Ed Burns wrote:

> Gang -
>
> Ed and I spoke about this yesterday.  Ed has come up with a solution
> that will allow us to restore ComponentHandler to the public API
> without also having to pull the entire implementation into the API.
> The solution leverages a new TagHandlerHelper contract - the public
> ComponentHandler class will delegate all of the thorny work to a
> TagHandlerHelper.  The actual TagHandlerHelper implementation will
> live in the JSF implementation.
>
> I think that this is a good compromise that balances the needs for a
> ComponentHandler base class with the desire to keep the API as free
> of implementation as possible.  Thanks very much Ed for getting this
> solution in even at this late date!
>
> Last night I took a closer look at the new public ComponentHandler
> API (in the Mojarra trunk) and also at Trinidad/ADF Faces
> ComponentHandler (and ComponentSupport) usage.  I found a few diffs
> between the legacy Facelets APIs and the JSF 2.0 APIs that I wanted
> to share with the EG.
>
> 1. ComponentSupport.isNew()
>
> This API was present in legacy Facelets but as far as I can tell is
> no longer present in JSF 2.0.  Custom handler implementations use
> this method to determine whether a component is newly created.  If
> the component is newly created, the handler might do some work to
> further initialize the component.  On the other hand, if the
> component is not newly created, the handler might instead short-
> circuit and not muck with the component.
>
> This is a fairly common use case (shows up in both Trinidad and ADF
> Faces), so I think we need something here - if not a public API,
> then at least a recommended alternative.  Note that
> ComponentSupport.isNew() actually has a trivial implementation:
>
>>    public final static boolean isNew(UIComponent component) {
>>        return component != null && component.getParent() == null;
>>    }
>
> So one option would be to replace calls to ComponentSupport.isNew()
> with code like the above.  Though of course that does mean pushing
> some assumptions about component tree wiring out into user code.

I agree, this should be in.

>
>
> 2. ComponentHandler.applyNextHandler()
>
> The legacy Facelets ComponentHandler contract included the following
> API:
>
>>    protected void applyNextHandler(FaceletContext ctx, UIComponent c)
>
> Though this is not present on our new JSF 2.0 ComponentHandler class.
>
> ComponentHandler implementations typically override this if they
> need to do pre/post-processing before/after the child tags are
> applied.
>
> I think we should be able to add this back into the JSF 2.0
> ComponentHandler fairly easily.  Just need the
> TagHandlerHelper.apply() implementation to call back into the
> ComponentHandler to apply the next handler.  (I think we are going
> to need to do this anyway, since the ComponentHandler has the
> reference to the next handler.)

And this one too.

>
>
> 3. TagHandler.findNextByType()
>
> The legacy Facelets TagHandler contract included the following API:
>
>>    protected final Iterator findNextByType(Class type)
>
> It appears this method is no longer present in the JSF 2.0 API.
>
> Custom TagHandler implementations need access to this API in cases
> where they need to perform special processing of their children.
> ADF Faces has a number of cases where we need to do this, so I would
> like to see if we can restore this API.
>
> Note that this method is not specific to ComponentHandler - non-
> component TagHandlers may need this as well.
>
> 4. TextHandler interface
>
> The typical way to to support TagHandlers (or ComponentHandlers) of
> the form:
>
> <foo>some text here</foo>
>
> Is to use findNextByType() in conjunction with the TextHandler
> interface.
>
> For example, the VerbatimHandler does this:
>
>>        StringBuffer content = new StringBuffer();
>>        Iterator iter =
>> TagHandlerImpl.findNextByType(this.nextHandler,
>>                TextHandler.class);
>>        while (iter.hasNext()) {
>>            TextHandler text = (TextHandler) iter.next();
>>            content.append(text.getText(ctx));
>>        }
>
> Without having access to the TextHandler interface, it is not
> possible to implement handlers that process child text.
>
> Fortunately TextHandler is just a trivial interface with two methods:
>
> - public String getText();
> - public String getText(FaceletContext ctx);
>
> And this interface is already present in the JSF 2.0 - but off in
> the ri.  Can we promote this out of the ri and into the API so that
> we can enable support for tags that contain text?  I don't see any
> way to support this use case without access to the TextHandler
> interface.
>
> 5. FacetHandler, AttributeHandler
>
> Okay, these two are probably fairly ADF Faces-specific...  ADF Faces
> has its own page template component.  Usage looks something like this:
>
>>  <af:pageTemplate template="path/to/some/template/file">
>>      <f:attribute name="foo" value="bar">
>>      <f:facet name="foobar">
>>          <h:outputText value="Hello, World!"/>
>>      </f:facet>
>>  </af:pageTemplate>
>
>
> In the ComponentHandler subclass for <af:pageTemplate>, we perform
> some pre-processing of attributes/facets before we process the
> template file.  In order to do this, we call findNextByType() twice
> - once with AttributeHandler.class to find all of the attributes,
> and then a second time with FacetHandler.class to grab all of the
> facets.
>
> This works beautifully in legacy Facelets, where FacetHandler/
> AttributeHandler are public classes, but not so well in JSF 2.0,
> since these classes are no longer part of the public API.
>
> I understand the desire not to include these handler implementation
> classes in the public API - ie. I understand why we want to keep as
> much implementation as possible in the ri and not in the API.
> However, assuming we cannot expose the existing FacetHandler/
> AttributeHandler classes in the API... Is there any chance that we
> can add marker interfaces to the public API?  (Doesn't have
> necessarily have to be a marker interface - an FacetHandler
> interface that returns the facet name would be tremendously useful
> for us.)  If we can have some way to find child attributes/facets,
> this would allow us to port our af:pageTemplate component to JSF
> 2.0.  Since this is a key component for us - used throughout Oracle
> products - being able to support will definitely help Oracle's
> ability to upgrade to JSF 2.0.
>
> Oh, of course, if we are willing to attempt to get these last minute
> additions in, in the interest of time I would be more than happy to
> provide patches/changebundles/spec prose for these APIs!
>
> Andy
>
> Andy Schwartz wrote On 2/27/2009 7:39 PM ET:
>> Gang -
>>
>> I realize that it is way beyond late for me to be sending this
>> email, but I think that this issue is significant enough that it is
>> worth raising even at this late point.
>>
>> Last year when we discussed which Facelets classes should be
>> included in the JSF 2.0 API, one of the questions was whether
>> ComponentHandler (and ComponentConfig/Support) should be included
>> in the public API.  At the time I asked that these be included as
>> Trinidad makes use of these API (or, in the case of
>> ComponentSupport, parts of these APIs).  However, Ed was reluctant
>> to add these to the JSF 2.0 public API.  I believe the reasoning was:
>>
>> 1. Our new composite components functionality should dramatically
>> reduce the # of cases where component authors need to write custom
>> tag handlers.
>> 2. In cases where custom tag handlers are necessary, custom
>> component author can implement their own handler solution, perhaps
>> by extending TagHandler instead of ComponentHandler.
>>
>> While #1 might be an option for many custom components, it is not
>> really an option for our existing Trinidad (and ADF Faces)
>> components.  These are Java-based components/APIs with Java-based
>> Renderers - in many cases very complex Java Renderers. Composite
>> components are not a solution here.
>>
>> Unfortunately I did not have time to take a closer look a #2 until
>> very recently.  On closer examination, it seems to me that re-
>> implementing the functionality provided by ComponentHandler is non-
>> trivial - and possibly even impossible to do in a portable way (ie.
>> without depending on JSF implementation details).
>>
>> The non-trivial part to re-implementing a ComponentHandler is
>> providing a replacement for the component tree wiring logic.  This
>> includes behavior such as:
>>
>> - Searching the parent component to see whether an existing
>> component is present.  (ComponentSupport.findChildByTagId())
>> - Marking existing components for deletion.
>> (ComponentSupport.markForDeletion())
>> - Marking component instances as being newly created.
>> (ComponentSupport.MARK_CREATED)
>> - Cleaning up orphaned components.
>> (ComponentSupport.finalizeForDeletion())
>> - Creating the implicit wrapper component for facets with multiple
>> children. (ComponentSupport.addComponent())
>>
>> Also, when adding newly created components into the component tree,
>> there is some internal communication between FacetHandler and
>> ComponentHandler regarding where the newly created component should
>> be inserted (as indicated by FacetHandler.KEY).  However, this
>> communication is currently implementation-specific - a replacement
>> ComponentHandler implementation cannot participate in this wiring
>> without depending on internal behavior.
>>
>> Yikes!  This is a very large burden to place on custom component
>> authors.  Comparing this to JSP land, this is basically the
>> equivalent of asking custom component authors to re-implement
>> UIComponentClassicTagBase - clearly something that we would never
>> expect component authors to be required to do.
>>
>> Looking at the original documentation for Facelets, it seems clear
>> that ComponentHandler is considered to be part of the public API:
>>
>> https://facelets.dev.java.net/nonav/docs/dev/docbook.html#dev-meta-
>> component
>>
>> Similarly, the Apress "Myfaces and Facelets" book treats
>> ComponentHandler as a public API and includes a section devoted to
>> writing custom ComponentHandlers.
>>
>> I am concerned that by excluding this ComponentHandler the JSF 2.0
>> public API, we are taking away a long-standing Facelets public API,
>> and in the process, making it significantly more difficult for
>> component authors to upgrade existing components to JSF 2.0,
>> something we clearly want to avoid (ie. we want to keep the
>> migration path as smooth as possible to encourage upgrading).
>>
>> I am of course particularly concerned about the impact that this
>> might have on the ability to upgrade Trinidad/ADF Faces to JSF 2.0
>> (selfish, yes).  But my concerns are not limited to Trinidad/ADF
>> Faces... I did some poking around and I see that other component
>> sets have the same dependency on ComponentHandler.  For example,
>> RichFaces has some handlers that extend ComponentHandler:
>>
>> http://www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/apidoc/org/richfaces/taglib/ColumnTagHandler.html
>>
>> As does Tomahawk:
>>
>> http://myfaces.apache.org/tomahawk-project/tomahawk12/apidocs/org/apache/myfaces/custom/schedule/ScheduleTagHandler.html
>>
>> I suspect that any custom component that needs to perform
>> specialized attribute processing - including components which
>> support MethodExpression-based attributes - is going to need to
>> extend (or, at the moment, re-implement) ComponentHandler.  Rather
>> than potentially placing obstacles in the way of upgrading these
>> components to 2.0, I would like to ask that we re-think our
>> decision to not include ComponentHandler in the JSF 2.0 public API.
>>
>> For the sake of completeness, just wanted to add... Here at Oracle
>> we recently started an effort to move our ADF Faces JSP tags over
>> to Facelets.  As part of this effort we found a few other Facelets
>> APIs that would be tremendously helpful to our cause, but are not
>> currently in the JSF 2.0 public API.  These include:
>>
>> - com.sun.facelets.tag.TagDecorator
>> - com.sun.facelets.tag.jsf.core.AttributeHandler
>> - com.sun.facelets.tag.jsf.core.FacetHandler
>>
>> I can of course explain the use case for these in more detail, but
>> seems like it would be best to save that for another email.
>>
>> So, thoughts on ComponentHandler?  Is there any way that we can
>> possibly get this into the 2.0 API before we ship?
>>
>> Again, I do appreciate how late it is to be raising this (again).
>> I am sorry about the last minute nature of this request.
>>
>> Andy

--
Pete Muir
http://www.seamframework.org
http://in.relation.to/Bloggers/Pete






More information about the jsr-314-open-mirror mailing list