Writing reusable [fleXive] components

While [fleXive] builds on existing JavaEE 5 infrastructure, it integrates additional services that make writing components for [fleXive] applications even easier.

JSF components provide a simple and powerful way of providing additional functionality to existing applications, for example a forum or comment section. A component packages all Java code and web resources into a single JAR file that can be dropped into the lib/ directory of an existing flexive.ear file. After the next [fleXive] startup it is available to all applications contained in the [fleXive] archive.

The [fleXive] distribution contains a build target to create the directory structure of a standalone component, including a build file to compile and package the component.

To create a new component, open the command shell and go to the directory containing the [fleXive] distribution. Execute ant. You are greeted by the welcome screen of the flexive build tool. Enter component.create as the target name and supply the name of your component (e.g. test). When you confirm the input, a new component directory layout is initialized in the distribution's parent directory, in this case in ../test. Your screen should look approximately like this:

Buildfile: build.xml

info:
  [flexive]
  [flexive] Welcome to the flexive build tool. Feel free to use the following build targets:
  [flexive]
  [flexive] project.create
  [flexive]     Creates a new flexive project directory.
  [flexive]
  [flexive] component.create
  [flexive]     Creates a new flexive UI component directory.
  [flexive]
  [flexive] db.create
  [flexive]         Create or reset the database schema of a flexive division.
  [flexive]         Warning: if the schema already exists, it will be dropped (i.e. you will lose all data
  [flexive]         stored in the schema).
  [flexive]
  [flexive] db.config.create
  [flexive]         Create or reset the global flexive configuration schema.
  [flexive]
    [input] Please enter a target name, or quit to exit:
component.create

check:

component.create:
    [input] Name of the component you want to create:
test
  [flexive]
  [flexive] Please confirm your input:
  [flexive] Component name:      test
  [flexive] Base directory:      ../test
  [flexive]
    [input] Are these settings correct? ([y], n)
y
    [mkdir] Created dir: /tmp/test
     [copy] Copying 8 files to /tmp/test
     [copy] Copied 13 empty directories to 6 empty directories under /tmp/test
     [copy] Copying 1 file to /tmp/test
     [echo] Component test created successfully. The component root directory is
     [echo] ../test

                    

Change to your component directory in ../test. The directory structure is similar to a [fleXive] project, the main difference is that there is only one source folder since all classes will be packaged into one JAR file.

.
|-- build.xml
|-- resources
|   |-- META-INF
|   |   |-- faces-config.xml
|   |   |-- flexive-plugins-config.xml
|   |   `-- weblets-config.xml
|   |-- messages
|   |-- scripts
|   |   |-- library
|   |   |-- runonce
|   |   `-- startup
|   |-- templates
|   `-- weblets
|-- src
|   `-- java
`-- web

To check if your build environment is working, execute ant in the component's base directory. An (empty) component JAR file should now be created in dist/test.jar. You can open the component in your favourite IDE now and start adding classes, templates and web pages. If you move the component directory to another directory (e.g. to maintain components in a larger [fleXive] project) be sure to modify the path to the [fleXive] distribution in build.xml.

A JSF component is a JAR file that may contain the following elements:

META-INF/faces-config.xml

Registers JSF beans, components, validators, and navigation rules. Note that you can reference XHTML pages from within your JAR file thanks to the classpath resource resolver as described in the section called “Delivering XHTML pages from the classpath”.

META-INF/*.taglib.xml

Register your own Facelets templates. The templates are stored directly in the JAR file and are referenced relative to the META-INF directory. For example, consider the following JAR contents:

./META-INF/mycomponents.taglib.xml
./templates/button.xhtml

To register your button tag, the mycomponents.taglib.xml might look like the following:

<?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://www.mycompany.com/jsf/components</namespace>

    <tag>
        <tag-name>button</tag-name>
        <source>../templates/button.xhtml</source>
    </tag>
</facelet-taglib>

Facelets scans the classpath for *.taglib.xml files and will automatically provide the registered templates and components under the given namespace.

META-INF/flexive-plugins-config.xml

Defines [fleXive] JSF plugins, as described in the section called “The JSF plugin API”.

META-INF/weblets-config.xml

Contains the Weblets configuration if you want to deliver additional web resources like images or stylesheets. The weblets resources are stored in the JAR file like Facelets templates, but their base directory may be any package in the JAR file. For example, the following config file sets the weblets root directory of the [fleXive] components package to com/flexive/faces/weblets and registers the weblet provider for the URI /flexive-web-resources/:

                                        <?xml version="1.0" encoding="UTF-8" ?>
<weblets-config xmlns="http://weblets.dev.java.net/config">
    <weblet>
        <weblet-name>com.flexive.faces.weblets</weblet-name>
        <weblet-class>
            net.java.dev.weblets.packaged.PackagedWeblet
        </weblet-class>
        <weblet-version>@FLEXIVE_VERSION@</weblet-version>
        <init-param>
            <param-name>package</param-name>
            <param-value>
                META-INF.resources.flexive-faces
            </param-value>
        </init-param>
    </weblet>
    <weblet-mapping>
        <weblet-name>com.flexive.faces.weblets</weblet-name>
        <url-pattern>/flexive-web-resources/*</url-pattern>
    </weblet-mapping>
</weblets-config>
                                    

If you attach -SNAPSHOT to the weblet-version number, you can disable browser caching for development builds. Otherwise Weblets will add caching information and you have to change the version number to ensure that all clients will use the most recent version.

EJB3 components can be packaged in any JAR file and should be deployed automatically if included in the flexive.ear file. At the time of this writing, this mechanism was not working in current versions of Glassfish and JBoss unless you included an explicit ejb-ref.xml, so you have to add an explicit reference to the EJB JAR file in flexive.ear!/META-INF/application.xml if you use only EJB3 annotations. When you develop [fleXive] applications as described in Chapter 4, Writing [fleXive] applications , this is done automatically by the [fleXive] build system.

For further information on EJB packaging rules please refer to [Packaging EJB3 applications], which is also a chapter in the great [EJB3 in Action].