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/...
>
>
> As does Tomahawk:
>
>
http://myfaces.apache.org/tomahawk-project/tomahawk12/apidocs/org/apache/...
>
>
> 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