In my ongoing efforts to learn the JSF framework as thoroughly as possible, I decided to write a component, but, with the myriad of high quality components available, what was left for me to do? :P At the suggestion of my brother, who has been watching a similar effort underway in the Wicket space, I’ve decided to wrap Yahoo’s UI library. The problem I ran into pretty quickly, though, was that the documentation wasn’t too clear as to what I needed to make it happen (though it’s quite likely I was having an obtuse moment or three). There are a plethora of resources that discuss what needs to be done, but all seemed either incomplete or too disjointed (see disclaimer above). So, to help ameliorate that, let’s walk through wrapping Yahoo’s calendar component as a JSF component, step by step. Before I go much further, though, I must note that I am by no means an expert in this, so it’s likely that you’re going to see some less than ideal examples. So, without further ado…
When starting any project, it’s good idea to try to get a complete picture of what you’re going to need. In my efforts to wrap YAHOO.widget.Calendar, I found that I need to create following files:
There are other files in my project, but these are the pertinent ones for now. With which file you start when writing components is probably largely a matter of personal taste, but we’ll start looking at things with yuisf.tld, as that will define how our tag looks to the outside world, giving us a good idea of what we’ll need to do in the rest of the files. Here’s what the TLD looks like:
<?xml version="1.0" encoding="UTF-8"?><taglibxmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"version="2.1"><tlib-version>0.1</tlib-version><jsp-version>1.2</jsp-version><short-name>yuisf</short-name><uri>http://steeplesoft.com/yuisf</uri><display-name>YahooUIJsfTags</display-name><description>
Yahoo! User Interface JSF Tags This tag library contains tags which wrap
several of the Yahoo! UI components.
Most of this should be fairly self-explanatory, so we’ll skip down to the tag element. The first thing we do is give the tag a name, calendar (surprise, surprise), which will be the name used in your JSP templates. Next, we define the class that will implement this tag, com.steeplesoft.jsf.components.yui.calendar.CalendarTag. Skipping a bit more, we see one attribute element. This is where we define what attributes a user can set on our tag. For this tag, we declare a textField attribute, which is required.
CalendarTag implements our tag. Since we don’t need any JSF 1.2-specific features, and we want the tag to be available to a wider audience, we’ll target 1.1, which means that our class will need to extend UIComponentTag. Let’s take a look at that class now:
There are three methods that we need to override: getComponentType(), getRendererType(), and setProperties(UIComponent component). In our implementation of the first two methods, we simply return a public static String from UICalendar, which we’ll see in a moment. These values will be used to help tie the component in just a moment. The third method is <a title="quoth the Ryan Lubke">where the magic happens</a>. Since we want the component to be value binding aware, we set the textField attribute to rtexprvalue=false in yuisf.tld, and check to see if the value passed is a literal or value binding expression, and handle it appropriately. Is that overkill for this field? Most likely. ;) Note also, that we have accessors for each attribute exposed in the TLD.
UICalendar is the actual component. For no particularly compelling reason, I’ve chosen to extend javax.faces.component.UIPanel. Let’s take a look:
This class doesn’t do much of anything of interest, but it’s important for a couple of reasons. Via the constuctor and getFamily, more pieces are put in place to tie all of our files together to make our new component. We also defined a property and accessors for our textField attribute, which will make working with the component in Java code a bit nicer. Note also that public static Strings defined at the top. We’ve already seen these referenced once in our tag class, and we’ll see in a moment the final place these values are referenced.
All of this work is for naught if JSF doesn’t know how to render the component. We’ll do that now, via CalendarRenderer:
This class is the most interesting of all that we’ve done thus far, as this is where the user interface magic happens. It is via the renderer that the component is turned from Java source, TLDs, and view templating mark up into a real live HTML (in our case) widget. For those not familiar with the calendar component, here is what we want our output to look like:
var tf = document.getElementById("j_id_id15:test");
tf.value = formatDate(j_id_id18_cal.getSelectedDates());
var cal = document.getElementById("j_id_id18");
cal.style.visibility = 'hidden';
j_id_id18_cal = new YAHOO.widget.Calendar("j_id_id18_cal","j_id_id18");
j_id_id18_cal.onSelect = j_id_id18_calOnSelect;
var pos = YAHOO.util.Dom.getXY("img_j_id_id18");
var img_height = parseInt(YAHOO.util.Dom.getStyle("img_j_id_id18", "height"));
elem = YAHOO.util.Dom.get("j_id_id18");
elem.style.top = pos + img_height - 1 + "px";
elem.style.left = pos + "px";
elem.style.position = 'absolute';
Wow! That’s some pretty ugly markup, but what you get out of that generated mess is, in my opinion, worth it, and the user will never see that (unless he’s crazy enough to view the page source). That mark up, by the way, is generated by this template snippet:
The final piece to tieing this together is faces-config.xml:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
Yahoo! UI Calendar
</description><display-name>Yahoo! UI Calendar</display-name><component-type>com.steeplesoft.jsf.components.yui.calendar.Calendar</component-type><component-class>com.steeplesoft.jsf.components.yui.calendar.UICalendar</component-class><component-extension><renderer-type>CalendarRenderer</renderer-type></component-extension></component><render-kit><description>
Renderkit implementation for the Calendar component
Here we define both a component and a render kit. Note that component-type is the same as UICalendar.COMPONENT_TYPE, and component-class is our UICalendar class. For the render kit, component-family is what UICalendar.getFamily() returns (if you had a group of components that used the same renderer, each class would return the same string for its family). The renderer-type is that same as UICalendar.RENDERER_TYPE, and, of course, renderer-class points to our Renderer child.
With all of that done, we need to package our new component. In the component jar, you’ll obviously need the compiled Java classes, but you’ll also need the META-INF directory in the root of your jar (which is why I chose to put it in the root of my source directory). You are now ready to put the resulting jar (and it’s dependencies) in your web application and start using the component. Simple, eh? :)
While this gets a functioning component (and a pretty cool one at that), it’s certainly not feature complete, nor is it an example of how one should write a component. Hopefully, though, it will get you started writing your own components as it did me.
So what’s the future of this component? The short answer is, I’m not completely sure. All I know is that it will be open sourced somewhere. Discussions about where the project will live are pending, but I hope to have that nailed down pretty soon. If nothing else, I’ll host them here. Watch this space for more information on that.