Ryan Lubke's Blog

JSF Configuration Resource Ordering

Wednesday May 27, 2009

A common issue in JSF 1.1/1.2 was the inability to control the order in which faces-config.xml files were parsed when said files were included in a JAR file.  Why does ordering matter?  Consider the decoration of entities such as ViewHandler or Application.  If your application contains more than two ViewHandlers, you may wish to have the ViewHandler delegation chain configured in a certain order.
The same holds true for PhaseListeners.  A developer may wish to have PhaseListenerB execute before PhaseListenerA.

A stop-gap measure was implemented by Mojarra (MyFaces does the same I believe) where the ordering of META-INF/faces-config.xml documents was determined by the natural sort order of the JAR name that contained the file.  While this worked, it wasn't a perfect solution as you were then forced to rename the JAR files to achieve the desired result.

JSF 2.0 solves this by requiring implementations to support partial ordering of the configuration resources via the ordering element.
The ordering element offers a way for a single document to state it wishes to be ordered before or after a specific document, or a group
of documents.  Documents can be identified by the top-level name element.  It's imporant to note that there are two documents in configuration processing that are always processed in a specific order and as such the ordering element has no impact.  The implementation default configuration resource is always processed first and the WEB-INF/faces-config.xml (if present) is always processed last.

Given the above, let's start with an example straigh from the specification:

A.faces-config.xml:

<faces-config>
    <name>A</name>
    <ordering>
        <after>
            <name>B</name>
        </after>
    </ordering>
    <application>
        <view-handler>com.a.ViewHandlerImpl</view-handler>
    </application>
    <lifecycle>
        <phase-listener>com.a.PhaseListenerImpl</phase-listener>
    </lifecycle>
</faces-config>

B.faces-config.xml:
<faces-config>
    <name>B</name>
    <application>
        <view-handler>com.b.ViewHandlerImpl</view-handler>
    </application>
    <lifecycle>
        <phase-listener>com.b.PhaseListenerImpl</phase-listener>
    </lifecycle>
</faces-config>

C.faces-config.xml:
<faces-config>
    <name>C</name>
    <ordering>
        <before>
            <others />
        </before>
    </ordering>
    <application>
        <view-handler>com.c.ViewHandlerImpl</view-handler>
    </application>
    <lifecycle>
        <phase-listener>com.c.PhaseListenerImpl</phase-listener>
    </lifecycle>
</faces-config>
D.faces-config.xml:
<faces-config>
    <name>D</name>
    <application>
        <view-handler>com.my.ViewHandlerImpl</view-handler>
    </application>
    <lifecycle>
        <phase-listener>com.my.PhaseListenerImpl</phase-listener>
    </lifecycle>
</faces-config>


Looking over the four documents, we see that:
  • Document A is after document B
  • Document B has no ordering requirements
  • Document C is uses the others element to say it should be ordered
    before all the other documents that are being sorted
  • Document D has no ordering requirements
The resulting parse order may be:
  1. Implementation specific configuration resource
  2. Document C
  3. Document B
  4. Document A
  5. WEB-INF/faces-config.xml (if present)

Here's a couple other examples to illustrate an important point about the ordering.  When documents state they wish to be before or after another document, it may not necessarily be the case that the documents are ordered right next to each other.  I think the following examples will clarify what I mean:

Document A - <after><others/><name>C</name></after>
Document B - <before><others/></before>
Document C - <after><others/></after>
Document D - no ordering
Document E - no ordering
Document F - <before><others/><name>B</name></before>

The resulting parser order could be [F, B, D, E, C, A], but [F, B, E, D, C, A] would also be accurate.

Here's another:

Document <no id> - <after><others/></after><before><name>C</name></before>
Document B - <before><others/></before>
Document C - no ordering
Document D - <after><others/></after>
Document E - <before><others/></before>
Document F - no ordering

Possible parsing orders are:
  • B,E,F,<no id>,C,D
  • E,B,F,<no id>,C,D
  • B,E,F,C,<no id>,D
  • E,B,F,C,<no id>,D
An important note on that last example - if a document has ordering requirements, but no name, then the ordering requirements will be ignored.

Now, there are most likely going to be cases where the resulting partial parsing order doesn't quite fit with what an application needs.
In that case, the developer can fallback to another new element called absolute-ordering.  This element is only valid within the WEB-INF/faces-config.xml and will be ignored in all other cases.  The use of this element allows the developer complete control over the order that faces-config documents will be processed.

Here's a simple example:
<faces-config>
    <absolute-ordering>
        <name>C</name>
        <name>A</name>
    </absolute-ordering>
    .
    .
    .
</faces-config>

In this case, the parsing order would be:
  • Implementation specific configuration resource
  • Document C
  • Document A
  • WEB-INF/faces-config.xml
It's pretty simple, however, developers should be aware that any documents that aren't explicitly referenced within the absolute-ordering element will not be processed.  Though it is possible to include those documents without having to enumerate them all individually.

Consider:
<faces-config>
    <absolute-ordering>
        <name>C</name>
        <others />
        <name>A</name>
    </absolute-ordering>
    .
    .
    .
</faces-config>
In this example, assuming we started with documents [A, B, C, D], then the resulting parse order may look like:

  • Implementation specific configuration resource
  • Document C
  • Document B
  • Document D
  • Document A
  • WEB-INF/faces-config.xml

Note that B/D could be interchanged.  The others element may appear any where within the absolute-ordering element, but it may only do so once.

[2] Comments
Like this post? del.icio.us | furl | slashdot | technorati | digg

JSF 2.0 passes final ballot!

Wednesday May 27, 2009

Per:  http://jcp.org/en/jsr/results?id=4939

Like this post? del.icio.us | furl | slashdot | technorati | digg

Unified Expression Language and JSF 1.2/2.0

Wednesday May 27, 2009

The Unified Expression Language in EE6 is getting updated to support arbitrary/parameterized method calls without having to use static EL functions.

Here's is a quick example.  Consider the following managed bean:

public class TestBean {
    private List<String> names = new ArrayList<String>();

    public String greetName(String name) {
        names.add(name);
        return "Hello, " + name;
    }

    public List<String> getNamesGreeted() {
       return names;
    }
}

and now consider the following fragment from a Facelet view:
<h:outputText value="#{bean.greetName('Bill')}" /><br />
<h:outputText value="#{bean.namesGreeted.size()}" />

The first outputText will display "Hello, Bill", and the second, displays the size of the collection of all the names greeted, which in this simple example, would be "1".

So what about parameterized MethodExpressions (i.e. <h:commandButton action="#{bean.doAction(arg1, arg2)}" ... />)?
Well, this is currently a work in progress by the EL implementation folks.  Stay tuned for updates on this particular topic.

The new EL is already available in GlassFish V3, so if you're using V3 promoted builds, you can start taking advantage of the EL now with JSF and no configuration is necessary.

If you'd like to use the new EL in GlassFish V2, you can, as long as you're not using JSP.  The JSP compiler performs static analysis of the page being compiled and will complain when it encounters parameterized expressions.  This means you'll need to use an alternative view technology such as Facelets.

The EL libraries are available at the following URLs:
Copy the two JAR files to ${GLASSFISH_HOME}/lib, then edit ${GLASSFISH_HOME}/domains/<domain_name>/config/domain.xml and add the following attribute to the java-config element:
classpath-prefix="${com.sun.aas.installRoot}/lib/el-api-2.1.2-SNAPSHOT.jar:${com.sun.aas.installRoot}/lib/el-impl-2.1.2-SNAPSHOT.jar"
If the classpath-prefix attribute has already been defined, then append these two jars after the existing entries.  This modification will require a restart of the domain.  After these steps are complete, you should be able to leverage the new EL features.

Lastly, I'd recommend reviewing the change log for the new expression langauge to get familiar with what it offers and its limitations.

Like this post? del.icio.us | furl | slashdot | technorati | digg