Kiss My App

Monday, May 23, 2005

Validators and Converters in Facelets

Want to wire in a specialized Validator into Facelets with only a few lines of code?

First, lets presume your validator is bound to your JSF Application under the id com.mycompany.RegExpValidator. It has two properties: a String: pattern, and a boolean: caseSensitive.

Now, with your application's Jar, add a single file with a taglib.xml extension:

<facelet-taglib>
<namespace>http://www.mycompany.com/jsf
<tag>
<tag-name>regexp</tag-name>
<validator>
<validator-id>com.mycompany.RegExpValidator</validator-id>
</validator>
</tag>
</facelet-taglib>


Done.

Now you can use it any page and Facelets will take care of wiring all of your properties for you:

<input type="text" jsfc="h:inputText" value="#{login.name}">
<my:regexp pattern="\w+" caseSensitive="false"/>
</input>


Facelets will automatically take care of handling EL also for your UIComponents, Converters, and Validators (any object really), so you could use the built in validateLength, passing in min="#{field.size}".

What to take from this is that there really isn't any need to write tags when Facelets works off of the bean properties of the object you provide it. But if you do want more control, there are base objects and interfaces that you can implement to pretty much do whatever you want in the document.

Sunday, May 22, 2005

Making Facelets mimic Tapestry

Facelets has one very easy way of making any component or any tag replace an existing HTML element. You can, for example, do something like this:

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
...
<span id="intact" jsfc="ui:remove">
This Text Will Be Removed.
</span>
....
</html>


With Facelets, id's are left in tact, and at compile time, the 'jsfc' attribute tells the compiler to instead handle this element as a ui:remove. The same could be done with your UIComponents (inputText, commandButton, etc), along with JSTL tags such as c:if or c:forEach.

Currently, c:forEach doesn't decorate-- meaning if you turn a <tr> tag into a c:forEach, then the <tr> will be omitted from the output. Having c:forEach instead decorate, keeping <tr> intact wouldn't be difficult at all and would simply require extending the ForEachHandler included with Facelets to write out some stuff before and after calling super.apply(FaceletContext,UIComponent).

One drawback/benefit of Facelets is that expressions can be embeded within the page and don't require an element to capture their output. So things like this can be done:

<span class="highlight">#{login.error}</span>

In this case, the element span would be left intact as the designer created, and the #{login.error} would be evaluated to the rendered output.

Great care has been given to handling 'template' text where the content isn't a special tag, but may include dynamic parts. This has been highly optimized to work in conjuction with JSF's lifecycle.

More samples to come soon--

Anyone else going to JavaOne also this year?

Monday, May 16, 2005

Facelets: Templating

Pick your poison. Currently Facelets offers 3 different ways to modularize and decorate your pages/components.

  • Tag Files

  • Decorators

  • Includes


Preface

Facelets is founded on the idea of compositions. This means that a UIComponent tree can be defined in multiple Facelet pages and executed in part or whole. Some other frameworks, like Tapestry, may define a single component within a page, Facelets instead marks the root of a branch of child components-- a composition if you will.

Text before will be removed.
<ui:composition>
#{dynamic.text}
<h:inputText id="myText" value="#{foo.bar}"/>
</ui:composition>
Text after will be removed.

This means you can have an easily viewable HTML document (body/css/js) and all, but only use a portion of the page to define the reusable composition.


Templates

Compositions have a single attribute, "template", that can be used the same way that Struts Tiles does. Lets modify the composition example above for templates:


Text before will be removed.
<ui:composition template="/templates/menu.xhtml">
<ui:define name="title">
#{dynamic.text}
</ui:define>
<ui:define name="body">
<h:inputText id="myText" value="#{foo.bar}"/>
</ui:define>
</ui:composition>
Text after will be removed.

Now for the template--

Template Text before will be removed.
<ui:composition>
This Text will show up
<ui:insert name="title">
Default Title Text
</ui:insert>
This Text will also show up
<ui:insert name="body">
Default Body Text
</ui:insert>
So will this text
</ui:composition>
Template Text after will be removed.

When the Facelet is 'applied' and the tree is built, the template will be weaved in, using the default text/components if the definitions aren't passed. This functionality is the foundation of Facelet templating and has proven to be quite fast.


Includes

This is probably the most familiar method of modularizing content. This allows you to include another Facelet into the UIComponent tree.


<span id="leftNav">
<ui:include src="/WEB-INF/siteNav.xhtml"/>
</span>

The navigation that the include is pointing at could be an XML document with namespaces, or an XHTML page with namespaces that uses the 'ui:composition' tag as described above with templates.


Includes can also have child 'ui:param' tags that work the same as they do with JSP with a name and value attribute. These name/value pairs will be bound and passed to the included Facelet when the UIComponent tree is built:


<span id="leftNav">
<ui:include src="/WEB-INF/siteNav.xhtml">
<ui:param name="user" value="#{currentUser}"/>
<ui:param name="page" value="home"/>
</ui:include>
</span>


Decorators

I previously wrote about 'templates' with compositions. Decorators behave exactly the same way, except that you are inlining the template into the page:


Text before will show up
<ui:decorate template="/templates/menu.xhtml">
<ui:define name="title">
#{dynamic.text}
</ui:define>
<ui:define name="body">
<h:inputText id="myText" value="#{foo.bar}"/>
</ui:define>
</ui:decorate>
Text after will show up

This has practical uses where it doesn't make sense to abstract out a composition into a separate document, but would still like to take advantage of templating.


Tag Files

Tag files are no different than any other page. This means that your tag file can be as simple as something like this:


<!-- this is the whole file! -->
<composition xmlns="http://java.sun.com/jsf/facelet">
#{user.login} on page #{page}
</composition>

You can note that I'm using the same param's that were defined in the 'include' example to prove a point. The include with params has the same behavior defining a tag:

<my:echo user="#{currentUser}" page="home"/>

You will get some performance gain by defining tags instead of using an include because the attributes are wired at compile time, where an include must fetch its child params on each execution.


At this point, you have to wonder how you go about specifying or binding files to tags. Tags must be defined in a Facelet tag library, such as:


<facelet-taglib>
<namespace>http://www.mycompany.com/jsf</namespace>
<tag>
<tag-name>echo</tag-name>
<source>tags/echo.xml</source>
</tag>
</facelet-taglib>

As a side note, tag libraries can either be placed in the META-INF directory of your jar (same as a faces-config.xml), or specified in your application's web.xml.


That's it for now, more to come soon!

Sunday, May 15, 2005

Facelets

I've reappeared from the lab with a new toolkit for developing JavaServer Faces applications; it's called "Facelets". I've recently opened project page at Java.net, https://facelets.dev.java.net/.


Backstory


I, like many in the corporate world, will forever be stuck behind the technology curve thanks to vendor platforms *cough* BEA *cough*. I've been participating in the JSP 2.1 and JSF 1.2 alignment but was constantly reminded that I would never be able to use the technology I was helping to steer for about another 2 years. This assumption is based on the fact that we will only, maybe, be getting JSP 2.0 support this fall with Weblogic 9.0, and that's only if there aren't a bunch of issues with the platform. We've been running on 8.0 now for what seems to be 2 years, and that platform has JSP 1.2 support with an odd interpretation of the Servlet 2.3 spec.


About Facelets


Facelets is a clean slate on the JSP standard if you will. To the JSP developer/designer, things seem extremely normal if you are familiar with JSPX (xml compliant JSP). The major benefit of Facelets is that it's geared at utilizing JSF technology based on the interweaving/tree creation that must occur under the JSF 1.2 specification. Here's a sample taglib file for Facelets.

<facelet-taglib>
<namespace>http://www.mycompany.com/jsf
<tag>
<tag-name>bar</tag-name>
<component>
<component-type>javax.faces.Data</component-type>
<renderer-type>com.mycompany.Bar</renderer-type>
</component>
</tag>
</facelet-taglib>



Why Facelets Will Succeed


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


While some other frameworks are out there attempting to work with JSF components, they are all too 'middle' ground to be practical. Who wants to re-define their UIComponent's behavior or properties in yet another XML file or properties file? Facelets just does it for you under the JSF 1.2 specification.


I spent a while this afternoon getting Hans Bergsten's "Improving JSF by Dumping JSP" hangman example working under Facelets. With Facelets, I was able to retain the editability factor that he had proposed (same as with Tapestry's jwcid attribute), and reduce page declaration down to a single document without any of the issues he described.


On one hand, just the fact that I was able to swap out all the pages/component definitions within JSF without modifying any of the Java code is a real testament to the flexability of the JSF framework. Secondly, with the above taglib, instead of defining his 'bar' component multiple times within a separate XML file (as his framework uses), you can use your custom 'bar' component like so:


<m:bar id="letters" value="#{visit.letters}" var="letter">
<h:column>
<h:graphicImage value="#{letterImages[letter]}" />
</h:column>
</m:bar>

Facelets automatically takes care of all of the property mappings/valuebindings, validators, listeners, etc-- for you.


I'm not even going to get into the cool templating/decorator features built into Facelets. I'm going to save that for another blog :-)