9 jun 2008

Packaging JSF custom tags with Facelet support

Today we'll take a look at packaging our JSF custom tags into a JAR file. It's not hard to do, though it may seem quite tricky for the first time.
We're not telling a word about JSF custom components programming, but on later packaging of your already created tags (or non-UI components). There are just a few things we have to keep in mind: first, our custom tags should have a public static final String COMPONENT_TYPE variable that uniquely identifies the component; e.g. suppose we've a component tag:
package foo.bar.jsf.component.taglib;

public class MyComponentTag {
  public static final String COMPONENT_TYPE = "myCompany.MyComponent";

  public static final String MY_TEST_PROPERTY_ATTRIBUTE = "myProperty";

  private ValueExpression myProperty;

  public String getComponentType() {
    return COMPONENT_TYPE;
  }

So far, suppose we've implemented MyComponent using the standard approach and providing a MyComponent class and a MyComponentTag class.

Now let's look for what we need for packaging, three config files that will be packaged under META-INF folder in our JAR:
1. a faces-config.xml file
2. a mycompany.tld file (tag library descriptor)
3. in case we want to use our tags with Facelet, we need to provide a myCompany.taglib.xml file

We need to register our custom components providing a faces-config.xml file (JSF scans for all files named faces-config.xml under META-INF folders in all the JAR's in the classpath):
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
  <!-- Converters -->
  <converter>
    <converter-id>myCompany.myConverterId</converter-id>
    <converter-class>foo.bar.components.jsf.validator.SimpleConverter</converter-class>
  </converter>

  <!-- Components -->
  <component>
    <display-name>My Company Custom tag</display-name>
    <component-type>myCompany.myCustomTag</component-type>
    <component-class>foo.bar.components.jsf.taglib.MyComponent</component-class>
  </component>

  <!-- Validators -->
  <validator>
    <validator-id>myCompany.myValidatorId</validator-id>
    <validator-class>foo.bar.components.jsf.validator.SimpleValidator</validator-class>
  </validator>
</faces-config>


Our Tag Library Descriptor file myCompany.tld:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>mc</short-name>
  <uri>http://mycompany.net/jsf/components</uri>
  <description>MyCompany JSF custom components</description>
  
  <tag>
    <name>myCompany.MyComponent</name>
    <tag-class>foo.bar.jsf.component.taglib.MyComponentTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
      <name>myProperty</name>
      <required>true</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
  
  <!-- other components -->

</taglib>

Of course, you have to replace the values under tag according to your component particular needs. Anyway, let's briefly explain what this file says:

  • shortName will be the tag namespace used in your JSP/HTML files

  • uri will stand for the uri you use to import the tag into your namespace

So, given the previous TLD file, we should use the following namespace in our HTML files:
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:mc="http://mycompany.net/jsf/components">
...
</html>


And finally, and just if we want to use our new-fashioned tags with Facelet, we have to provide a myCompany.taglib.xml file. That file is conceptually similar to the TLD file, it declares the tags and attributes:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">

<facelet-taglib>
  <namespace>http://mycompany.net/jsf/components</namespace>

  <tag>
    <tag-name>myComponent</tag-name>
    <component>
      <component-type>myCompany.MyComponent</component-type>
      <renderer-type>myCompany.MyRenderer</renderer-type>
    </component>
  </tag>

</facelet-taglib>

Watch out! the component-type element must match the COMPONENT_TYPE constant defined in the tag .java file.

That's all! Creating and placing this file in the META-INF folder of your component JAR will allow you to reuse the components in an easy way.

No hay comentarios: