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.

5 jun. 2008

Howto: Setup Spring for Hibernate Annotations

Today, we'll explore how to setup the Spring ApplicationContext to use annotation-driven Hibernate mappings.
Hibernate mappings should be specified in any of the following:

  • Hibernate XML mapping files

  • XDoclet

  • Hibernate Annotations

Hibernate Annotations is my preferred way to map my entity classes, since they don't require any external file (thus keeping mapping info in your Java files), is fully integrated with all Hibernate mapping capabilities and Hibernate documentation encourages us to use this kind of configuration because it's more efficient.
Annotation driven mapping in Hibernate uses the standard JPA API annotations and introduce some specific extensions to deal with some Hibernate features. You can find a full reference in the official documentation.
The Spring (version 2.5) applicationContext.xml file used to configure an annotation-driven SessionFactory should look like this:
...
  <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.AnnotationSessionFactoryBean">
    <property name="dataSource">
      <ref bean="dataSource" />
    </property>
    <property name="annotatedClasses">
      <util:list>
        <value>foo.bar.model.MyEntity</value>
        <value>foo.bar.model.AnotherEntity</value>
        <value>...</value>
      </util:list>
    </property>
    <property name="hibernateProperties">
      <util:properties location="hibernate.properties Location">
    </property>
  </bean>
...

Unfortunately, Spring's AnnotationSessionFactoryBean doesn't accept wildcards in the annotatedClasses property (since it's implemented as Class[] instead of Resource[]) and the annotatedPackages property is not intended to specify the package containing our annotated entities but to 'add package level annotations at the class leve' (I don't really understand this ;-) ).
But don't worry, we can extend AnnotationSessionFactoryBean to achieve what we want like this:
public class ExtendedAnnotationSessionFactoryBean extends
 AnnotationSessionFactoryBean {

  private String[] basePackages;
  private ClassLoader beanClassLoader;

  public void afterPropertiesSet() throws Exception {
    Collection<Class<?>> entities = new ArrayList<Class<?>>();
    ClassPathScanningCandidateComponentProvider scanner = this.createScanner();
    for (String basePackage : this.basePackages) {
      this.findEntities(scanner, entities, basePackage);
    }
    this.setAnnotatedClasses(entities.toArray(new Class<?>[entities.size()]));
    super.afterPropertiesSet();
  }

  private ClassPathScanningCandidateComponentProvider createScanner() {
    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
    scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
    return scanner;
  }

  private void findEntities(ClassPathScanningCandidateComponentProvider scanner,
                            Collection<Class<?>> entities, String basePackage) {
    Set<BeanDefinition> annotatedClasses = scanner.findCandidateComponents(basePackage);
    for (BeanDefinition bd : annotatedClasses) {
      String className = bd.getBeanClassName();
      Class<?> type = ClassUtils.resolveClassName(className, this.beanClassLoader);
      entities.add(type);
    }
  }
  
  public void setBasePackage(String basePackage) {
    this.basePackages = new String[] { basePackage };
  }

  public void setBasePackages(String[] basePackages) {
    this.basePackages = basePackages;
  }

  public void setBeanClassLoader(ClassLoader beanClassLoader) {
    this.beanClassLoader = beanClassLoader;
  }

}

We don't need to inject the beanClassLoader property if we don't want to, thus using the default ClassLoader. This happens because we're using ClassUtils.resolveClassName() to get the Class objects, and the Javadoc on this method stands that "the class loader to use may be null, which indicates the default ClassLoader". With that in mind, we can use the following applicationContext setup:
...
  <bean id="sessionFactory"
        class="foo.bar.MyAnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="basePackages">
      <util:list>
        <value>foo.bar.model</value>
      </util:list>
    </property>
    <property name="hibernateProperties">
      <util:properties location="hibernate.properties Location">
    </property>
  </bean>
...

That's all, with that, Hibernate will inspect and map all the classes in package foo.bar.model having the required annotations (@Entiy or @MappedSuperclass).

28 may. 2008

Reflection & Annotations

This post presents a simple (yet powerful) way to combine reflection and annotations to obtain all the methods present in a class' hierarchy marked with a given annotation.

package bar.foo.utils;

public class ReflectionUtils {

  /**
  * Enforce non-instatiability
  */
  private ReflectionUtils {}

  /**
   * Get all methods annotated with the specified annotation
   * searching on the leaf class and all superclasses.
   */
  public static Method[] getAllAnnotatedMethods(
      Class targetClass, Class annotationClass) {
    List list = new ArrayList();

    // traverse inheritance hierarchy
    do {
      Method[] methods = targetClass.getDeclaredMethods();
        for (Method method : methods) {
          if (method.isAnnotationPresent(annotationClass))
     methods.add(method);
        }
        targetClass = targetClass.getSuperclass();
    } while (targetClass != null);

    return (Method[]) list.toArray(new Method[list.size()]);
  }

}


It could be very useful in a variety of scenarios, e.g. auditing: by just annotating the getters in the audited entity, we'll be able to keep track of the values/changes with a few lines of code:

public class Entity extends BaseEntity {
  private Integer id;
  private MyProperty myProperty;
  
  // we don't want to audit id!
  public Integer getId() {return id;}

  // but we do want to audit myProperty
  @Auditable
  public MyProperty getMyProperty {return myProperty;}
}

...

public class AuditManager {
  public void auditEntity(BaseEntity myEntity) {
    Class entityClass = myEntity.getClass();
    Class annotationClass = Auditable.getClass();
    Method[] auditGetters = ReflectionUtils.getAllAnnotatedMethods(
                                      entityClass, annotationClass);
    
    for (Method method : auditGetters) {
      // audit logic here
    }
  }

20 feb. 2008

Hello World!

That's it, my way to start this blog space is to greet the Wild Wide Web in a familiar fashion

Hello World!

I pretend this blog to be a space to find useful information related to J2EE technologies. Of course, I'll focus on the topics I had trouble with and I found poorly documented (despite the long hours sailing the Web). I don't think I'm able to contribute with manuy fresh, innovative stuff, but I'm scatterbrained and this is a good place to write down my notes for later searchings.

We'll talk about Hibernate, Spring, JSF, Velocity, XHTMLRenderer, JUnit, EasyMock, Maven, CSS3...

See you later, navigator!