[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