September 09 2008
Create a Common Facelets Tag Library: Share it across projects
Tutorial - Step By Step
If you’ve learned to use JSF Facelets to create on-the-fly, simple components using XHTML, then you probably have a whole slew of custom components that need to be copied between various projects, and can be somewhat painful to keep up to date. You may have tried to move them into a jar file, but Facelets can’t find them there (without some help from us.)
*The author of this article has requested feedback on the usability of this article. Please post questions, improvements, and/or comments.
Goals
The intent of this tutorial is to explain how to create a packaged jar file, which can be referenced from multiple projects. and which contains all of your tag components and classes for easier maintenance.
(Please note that you may still include non-xhtml based components in this tag library, this does not limit you to use only xhtml facelets.)
Download the following archive
- Facelets Jar: jsf-facelets.jar (1.1.14 was used in this tutorial)
Instructions:
- Create a new Java Project. We will call it “facelets-taglib-common”
We recommend the title for your project should be the same as your tag library, since this will be the new home of those custom (shiny) components. - Extract the Facelets archive and copy “jsf-facelets.jar” into your project. Make sure that it is added to the class path.
- Copy and paste the following source files into your project.
- Create your facelets-taglib.common.xml definition file.
- Make necessary additions to web.xml
- Create your first tags.
When you are finished with this tutorial, you should have the following directory structure:
facelets-taglib-common/ +—JavaSource/ | | CustomResourceResolver.java | - | +—lib/ | | jsf-facelets.jar | - | +—META-INF/ | | facelets-common-taglib.xml | | facelets-common-taglib.tld | | MANIFEST.MF | | | +—taglib/ | | analytics.xhtml | | doctype.xhtml | | your_custom_tag.xhtml - -
—-
CustomResourceResolver.java
This is a required utility class to allow Facelets to find resources that are not in your project folder, but instead, anywhere on the build path.
Put this file in your source folder. The reason putting your XHTML custom components and tag XML files does not work out of the box is because Facelets uses a strict ResourceResolver. The default ResourceResolver looks only in the path of your current project / War. Fortunately, however, we can override the default behavior.
import com.sun.facelets.impl.DefaultResourceResolver; import com.sun.facelets.impl.ResourceResolver; public class CustomResourceResolver extends DefaultResourceResolver implements ResourceResolver { @Override public URL resolveUrl(String resource) { URL resourceUrl = super.resolveUrl(resource); if (resourceUrl == null) { if (resource.startsWith("/")) { resource = resource.substring(1); } resourceUrl = Thread.currentThread().getContextClassLoader().getResource(resource); } return resourceUrl; } }
—-
facelets-taglib-common.xml
This file defines your tag-library to facelets, it is required. See the facelets documentation. After this step, you should be able to package and export your project as a Jar file.
This file needs to be located in your /facelets-taglib-common/META-INF/ directory.
<?xml version="1.0"?> <!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "facelet-taglib_1_0.dtd"> <facelet-taglib> <namespace>http://www.ocpsoft.com/facelets-common</namespace> <tag> <tag-name>analytics</tag-name> <source>analytics.jspx</source> </tag> <tag> <tag-name>doctype</tag-name> <source>doctype.jspx</source> </tag> </facelet-taglib>
—-
facelets-taglib-common.tld (optional)
This file describes your tag-library for your IDE’s autocompletion, and for Validation, so that you can check during development to ensure that your tags are being properly used.
Note**: To enable autocompletion in your IDE, you probably need to copy this file into your own Web Application’s WebContent/META-INF/taglib/ directory, this does not affect Facelets.
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor"> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>rest</short-name> <uri>http://www.yoursite.com/facelets-taglib-common</uri> <display-name>My Common Tag Library</display-name> <tag> <name>analytics</name> <tag-class>common/analytics.jspx</tag-class> <body-content>JSP</body-content> <description> Render a google analytics identifier tag. </description> <attribute> <name>siteId</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <type>java.lang.String</type> <description> Your unique google site-id, eg: UA-4723***-* </description> </attribute> </tag> <tag> <name>doctype</name> <tag-class>common/doctype.jspx</tag-class> <body-content>JSP</body-content> <description> Render an XHTML doctype declaration. </description> </tag></taglib>
—-
web.xml
We need to make two additions to your Web Application’s web.xml file in order for this to work. Assuming that you have already installed Facelets into your faces-config.xml file, you also need to do two things here:
- Add your tag library XML file to the list of Libraries that Facelets will load.
- Override the default ResourceResolver
After this step, you should have a working configuration. Just make sure that your facelets-taglib-common.jar is on the class path, or that you have referenced the new taglibrary project as a dependency.
<context-param> <param-name>facelets.LIBRARIES</param-name> <param-value> /META-INF/taglib/facelets-taglib-common.xml </param-value> </context-param> <context-param> <param-name>facelets.RESOURCE_RESOLVER</param-name> <param-value>CustomResourceResolver</param-value> </context-param>
—-
Additional Resources:
Just in case you’re wondering how we did doctype and analytics, here is the source:
analytics.xhtml
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- THIS FILE IS LICENCED UNDER THE GPL3 Authors: Derek Hollis Lincoln Baxter, III Version: 1.2 Date: 2008/05/04 --> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jstl/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" version="2.0"> <ui:composition> <h:outputText value='<script type="text/javascript"> ' escape="false" /> <h:outputText value='var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.") ' escape="false" /> <h:outputText value='document.write(unescape("%3Cscript src=' " + gaJsHost + "google-analytics.com/ga.js' type=' text/javascript' %3E%3C/script%3E")) ' escape="false"/> <h:outputText value='< /script> ' escape="false" /> <h:outputText value='< script type="text/javascript"> ' escape="false" /> <h:outputText value='var pageTracker = _gat._getTracker("#{siteId}") ' escape="false" /> <h:outputText value='pageTracker._initData() ' escape="false" /> <h:outputText value='pageTracker._trackPageview() ' escape="false" /> <h:outputText value='< /script> ' escape="false" /> </ui:composition> </jsp:root>
doctype.xhtml
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- THIS FILE IS LICENCED UNDER THE GPL3 Authors: Derek Hollis Lincoln Baxter, III Version: $1.0$ Date: 2008/05/04 --> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jstl/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" version="2.0"> <ui:composition> <h:outputText value='<?xml version="1.0" encoding="UTF-8"?> ' escape="false" /> <h:outputText value='< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ' escape="false" /> </ui:composition> </jsp:root>
—-
That should be everything. You should now be able to store your common facelets tags and components in a centralized location, allowing for re-use across projects and teams.

I did something similar recently for a project I worked on. The cool thing with Tomcat is that you don’t need to declare the taglib in the target project at all; it will be loaded automatically during startup (now I have to check again if that was a Tomcat specific feature or not, I don’t remember :p).
That’s correct! I’ve packaged the taglib with the JAR file and although Facelets complains, it still find it:
Sep 11, 2008 12:14:32 AM com.sun.facelets.FaceletViewHandler initializeCompiler
SEVERE: Error Loading Library: /META-INF/taglib/facelets-common-taglib.xml
java.io.FileNotFoundException: /META-INF/taglib/facelets-common-taglib.xml
at com.sun.facelets.FaceletViewHandler.initializeCompiler(FaceletViewHandler.java:272)
at com.sun.facelets.FaceletViewHandler.initialize(FaceletViewHandler.java:161)
at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:537)
at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:109)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
———
But this later:
Sep 11, 2008 12:14:32 AM com.sun.facelets.compiler.TagLibraryConfig loadImplicit
INFO: Added Library from: jar:file:/WEB-INF/lib/facelets-common-taglib.jar!/META-INF/taglib/facelets-common-taglib.xml