2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Shale Tiger Extensions

Introduction

Are you running your web container on a Java SE 5 (code named "Tiger") or later JVM? If so, you can take advantage of several Shale features that are enabled by this underlying platform:

  • The ability to declare managed bean configuration with annotations, rather than requiring configuration in a faces-config.xml resource.
  • The ability of a backing bean to receive View Controller event callbacks to arbitrary methods declared with annotations, rather than requiring the backing bean to implement the ViewController interface and provide methods with the names defined by this interface.
  • The ability for JavaServer Faces components, converters, renderers,and validators to register themselves with the runtime system, without having to be declared in a faces-config.xml resource.
These features are enabled automatically if you include shale-tiger.jar in your web application.

Services Provided

Annotated Managed Beans

In a traditional JavaServer Faces application, managed beans must be declared in a faces-config.xml resource supplied by the application. In many cases, the supplied values are effectively constant -- for example, the name that the managed bean is known by is a dependency for other elements of the application (such as value binding expressions). In such cases, it would be very useful to be able to configure the managed bean name, and the scope this bean should be stored in, directly in the bean source code itself.

In addition to defining the characteristics of the managed bean itself, you can also use the @Value annotation to establish the initial value to which a field should be set. (You must supply a corresponding public property setter method.) This is not particularly useful for setting literal values, because you can accomplish the same result with a Java initialization expression on the instance variable itself. However, it is very useful when you want to specify an application-specific value binding expression, without requiring the developer to explicitly include the configuration in a faces-config.xml resource.

In some scenarios, an application developer will still want to override the characteristics that are specified via annotations. For this reason, any configuration information in a faces-config.xml resource, for a particular managed bean name, will override the corresponding settings defined by annotations.

Annotated View Controllers

The View Controller feature of Shale provides event callback services for several interesting lifecycle events:

  • init - Called when the view corresponding to this class has been created or restored.
  • preprocess - Called if this view is the one that will process a form submit.
  • prerender - Called immediately before this view will be asked to render itself.
  • destroy - Called after rendering, for all instances where init was called.
In the standard Shale implementation, this functionality is provided in the traditional way -- the backing bean interested in these callbacks is required to implement the org.apache.shale.view.ViewController interface, with fixed method names for each callback. With the Shale Tiger Extensions, however, this is no longer required (although it is, of course, still supported).

Instead, you implement a backing bean class with no requirements on extending a particular base class, or implementing a particular interface. Instead, you use the @View annotation on the class itself to say that it is interested in view controller callback events. Then, on any public method that takes no arguments, you use the @Init, @Preprocess, @Prerender, or @Destroy annotations to request callbacks, to that particular method, when the corresponding lifecycle event occurs. You are NOT required to use a particular method name for these callbacks. In addition, if your backing bean logic is not interested in one or more of the view controller callbacks, you are NOT required to provide a method that is marked with the corresponding annotation.

Annotated Component Registration

A standard JavaServer Faces runtime environment allows an application, or a component library, to register custom classes as JavaServer Faces components, converters, renderers,and validators, using the <component>, <converter>, <renderer>, and <validator> elements, respectively, in a faces-config.xml resource. The Shale Tiger extensions allow the implementation classes for these objects to register themselves by virtue of the existence of an annotation on the class, without requiring a configuration resource to be present. In each case, the class being registered must still implement the corresponding JavaServer Faces API (for example, a converter registered in this manner must still implement the javax.faces.convert.Converter interface).

Using The Tiger Extensions

To use any of the Shale Tiger Extensions in your application, you MUST run your web container on a Java SE 5 or later container, and MUST include the shale-tiger.jar resource in your web application.

To optimize performance at application startup, the Shale Tiger Extensions will ONLY examine classes (to see if they include the appropriate annotations) in the following lcoations:

  • Any class under /WEB-INF/classes.
  • Any class in a JAR file under /WEB-INF/lib that includes a META-INF/faces-config.xml resource, indicating that this JAR file is relevant to JavaServer Faces.

Using Annotated Managed Beans

To use the Annotated Managed Beans feature, you must use the @Bean annotation on the class itself, and set the managed bean name (required) and scope (optional). These elements correspond to the <managed-bean-name> and <managed-bean-scope> elements in a faces-config.xml resource. Then, within the class, you can optionally use the @Value annotation on a field to provide a literal value, or value binding expression, that will provide the initial value for the corresponding property.

Putting it all together, you might end up with a class that looks like this:

    package com.mycompany.mypackage;

    import org.apache.shale.tiger.managed.Bean;
    import org.apache.shale.tiger.managed.Scope;
    import org.apache.shale.tiger.managed.Property;

    // Define a managed bean named "mybean" to be put in session scope
    @Bean(name="mybean", scope=Scope.SESSION)
    public class MyBeanClass { // No required superclass or interface

        // Name a property that will be initialized via expression
        @Property(value="#{otherBean.otherProperty}")
        private String name = null;
        
        public String getName() { return this.name; }
        public void setName(String name) { this.name = name; }

    }

Using Annotated View Controllers

To use the Annotated View Controllers feature, you must use the @View annotation on the class itself. Then, you can use the @Init, @Preprocess, @Prerender, and @Destroy annotations on the methods that you wish to have notified when the corresponding lifecycle trips occur. You need to implement only the callbacks you are interested in (unlike the traditional implementation of an interface, where you must provide implementations for all of the defined method signatures).

A class that wishes to receive view controller callbacks via these annotations might look like this:

    package com.mycompany.mypackage;

    import org.apache.shale.tiger.view.Init;
    import org.apache.shale.tiger.view.Preprocess;
    import org.apache.shale.tiger.view.View;

    @View public class MyBean { // No required superclass or interface

        // Name your init() method whatever you want
        @Init public void myInit() { ... }

        // Same with the prerender() method
        @Prerender public void justBeforeRendering() { ... }

        // This class is not interested in preprocess or destroy
        // methods, so they are not defined

    }

Using Annotated Component Registration

To use the Annotated Component Registration feature, you must use annotations from the org.apache.shale.tiger.register package, as illustrated below:

An annotated component registration should look like this:

    package com.mycompany.mypackage;
    
    import javax.faces.component.UIComponentBase;
    import org.apache.shale.tiger.register.FacesComponent;

    @FacesComponent("my.component.type")
    public class MyComponent extends UIComponentBase {
    
        ...
        
    }

An annotated converter registration should look like this:

    package com.mycompany.mypackage;
    
    import javax.faces.convert.Converter;
    import org.apache.shale.tiger.register.FacesConverter;

    @FacesConverter("my.converter.id")
    public class MyConverter implements Converter {
    
        ...
        
    }

An annotated renderer registration should look like this (if the renderKitId attribute is not specified, the renderer will be registered with the standard HTML Basic renderkit):

    package com.mycompany.mypackage;
    
    import javax.faces.render.Renderer;
    import org.apache.shale.tiger.register.FacesRenderer;

    @FacesRenderer(renderKitId="my.render.kit.id",
                       componentFamily="my.component.family",
                       rendererType="my.renderer.type")
    public class MyRenderer extends Renderer {
    
        ...
        
    }

An annotated validator registration should look like this:

    package com.mycompany.mypackage;
    
    import javax.faces.validator.Validator;
    import org.apache.shale.tiger.register.FacesValidator;

    @FacesConverter("my.validator.id")
    public class MyValidator implements Validator {
    
        ...
        
    }