dev@javaserverfaces.java.net

[PROPOSAL] Facelets

From: Jacob Hookom <jacob_at_hookom.net>
Date: Tue, 10 May 2005 00:07:54 -0500

What are Facelets?
==============================
Facelet technology is an alternate ViewHandler implementation. Many
developers are actively looking for a Tapestry-like toolkit, with the
backing of an industry standard like JavaServer Faces-- Facelets hopes
to fill in that requirement while staying familiar to JSP developers
with JSTL implementations and EL-API use.

Facelets are defined in valid XHTML or XML, just as you would with
JSPX. Where Facelets differs is that it isn't burdened with
accomodating any legacy JSP API and specifically caters to the job of
creating and restoring UIComponent trees with developer friendly APIs
for rapid development-- a clean slate if you will.

I'm hoping to find a home for Facelets where it can stay closely aligned
with JSF-RI's goals.


Features
==============================
- Line/Tag/Attribute precise Error Reporting
- Compile-time EL Validation
- Plugging in UIComponents doesn't require any additional classes (like
JSP does)
- XML configuration files aren't necessary, but are available (ala
Taglib-lite)
- Doesn't require a JSP/Servlet Container, just JSF
- Very high performance-- I would say on par with compiled JSP if not faster
- Text fragments with inlined EL are allowed
- Text fragments with EL evaluate at render time, not at build time
- Full EL support, including Functions
- Facelets are agnostic towards ${} vs #{}
- Built in Templating framework, similar to Struts Tiles
- Can 'inline' multiple templates within a page (decorate a menu or panel)
- Can define UIComponent 'branches' in separate XHTML files (Compositions)
- Reserves the 'jsfc' attribute which acts the same as Tapestry's jwcid
  (Example: <input id="bar" type="text" jsfc="h:inputText"
value="#{foo.bar}"/>)
- Plugable Decorators to really make designer's job easy
  (Example: transform <input type="text"> --> <h:inputText/> at compile
time)
- Does *not* require any RenderKit dependencies


Sample Java Code
==============================
/* Snippets from FaceletViewHandler */
// grab our FaceletFactory and create a Facelet
FaceletFactory factory = FaceletFactory.getInstance();
Facelet f = factory.getFacelet(viewToRender.getViewId());

// populate UIViewRoot
f.apply(context, viewToRender);

// render view
viewToRender.encodeAll(context);

/* JSTL Catch Tag Logic for Facelets */
public void apply(FaceletContext ctx, UIComponent parent)
            throws IOException, FacesException, FaceletException,
ELException {
    try {
        this.nextHandler.apply(ctx, parent);
    } catch (Exception e) {
        if (this.var != null) {
            ctx.setAttribute(this.var.getValue(ctx),e);
        }
    }
}


JSP and Facelets
==============================
I look at what it takes to integrate JSF with JSP under it's Tag
execution model. Facelets has the concept of tags, but it's execution
model structured like Servlet Filters-- stateless and fast. No tag
pooling, no return codes, and no variable lifecycle to manage on each
execution. Everything is *highly* optimized and aligned for JSF's
UIComponent tree creation.

Adding a new UIComponent for use in a page can be done two ways:

public class MyLibrary extends AbstractTagLibrary {
    public MyLibrary() {
       super(NAMESPACE);
       this.addComponent("remoteTable", "javax.faces.UIData",
"com.company.RemoteTable");
    }
}

Compiler c = new SAXCompiler();
c.addTagLibrary(new MyLibrary());
c.setTrimWhitespace(true);
FaceletFactory factory = new BaseFaceletFactory(c);
Facelet facelet = factory.getFacelet("greeting.xhtml");

-or-

<!-- my.taglib.xml in jar's META-INF -->
<!-- ViewHandler will automatically include this -->
<facelet-taglib>
   <namespace>http://www.mycompany.com/jsf</namespace>
   <tag>
       <name>remoteTable</name>
       <component>
           <component-type>javax.faces.UIData</component-type>
           <renderer-type>com.mycompany.AJAXTable</renderer-type>
       </component>
   </tag>
   <tag>
       <name>validateEmail</name>
       <validator>
           <validator-id>com.mycompany.ValidateEmail</validator-id>
       </validator>
   </tag>
<facelet-taglib>


Finally...

Why Facelets will Work
==============================
Everyone wants to be more designer friendly, and Tapestry seems to be
the only choice developers are pursuing. On the other hand, JSF is the
standard everyone would like to have happen, but JSF needs a more
"pluggable" ViewHandler framework that is more designer/developer friendly.

Developers go through enough work defining
UIComponents/Converters/Validators in their faces-config.xml, and
Facelets *only* asks them to specify a name alias to plug their objects
into their pages (no XML necessary). JSP requires duplicating your
UIComponent's properties into a separate class *and* XML file, while
Facelets works off of the UIComponent instance itself to properly handle
Validators, Converters, Listeners, and Actions in accordance with the
JSF 1.2 spec, along with setting ValueExpressions versus literals on the
UIComponent's Attribute model auto-magically for you.

Jakarta Velocity has a great API model for environment-independent
execution and Facelets was modeled the same way. Unit testing JSF
components is extremely easy and doesn't require any Servlet container.
Simply initialize a FaceletFactory, and start grabing Facelet
instances. This could open the doors for more non-web uses for JSF
while providing a JSP-version independent view technology that can be
released and used as rapidly as JSF new versions.

Really, Facelets could be used the same as Thinlets or Macromedia's Flex
technology to define views/compositions/templates that are completely
unrelated to HTML or the web.

Conclusion
==============================
I know I can't make Facelets succeed without JSF-RI help, and I'm hoping
that I can include Facelets as part of JSF's Java.net project which I
would actively participate in the maintenance of as the JSF spec evolves.

I feel as though there needs to be a JSF technology out there that can
offer direction/ideas to JSF 2.0's whispered Tapestry behavior, while at
the same being able to aquire a larger JSF developer base from the
Velocity/Tapestry/JSF-naysayer population through plugable API's,
familiar features, and zero integration development.

Thanks for reading this lengthy proposal!

-- Jacob Hookom