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

Alaxander Smirnov asmirnov at EXADEL.COM
Wed Mar 4 00:17:25 EST 2009


I agree - the RichFaces library uses all of these methods also.
There is only one concern for me. The current implementation of the
findNextByType(Class type)  / TextHandler does not allows to have any
XML elements inside the tag:
<f:verbatim> This <b>is</b> a text</f:verbatim> does not works. That API
should be replaced by the something else with same functionality as JSP
BodyTag has.


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.
>
> 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.)
>
> 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






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