Friday, 19 January 2007

Using multiple faces-config.xml files in JSF

A client of mine is interested in the segmentation of an ADF Faces application. One file we were particularly interested in segmenting is the faces-config.xml file. Given that the faces-config.xml file includes all entries for managed beans, navigation and other elements it can quickly become huge and cumbersome in a medium to large application.

Given a bit of spare time I decided to research is it possible to split the faces-config.xml file into logical groups?

This post shares my experience in researching this issue. The value in this post is 2 fold; firstly from the issue it attempts to solve, but also second, the different avenues of research available when looking at JSF.

In a new standard JDeveloper ADF BC/JSF application workspace, the faces-config.xml file is placed under the ViewController project WEB-INF directory. At a guess I would say the FacesServlet is hardcoded to search and use the faces-config.xml file from the WEB-INF directory.

Such a guess requires a little research. A look at the Sun's JavaServer Faces Specification v1.1 (found here - select the Maintenance Release 1.1 link and follow the prompts) section "10.3.2 Application Startup Behavior" says that a JSF application on startup will undertake the following operations in order:
  • Search for all resources named "META-INF/faces-config.xml" in the ServletContext resource paths for this web application, and load each as a JSF configuration resource (in reverse order of the order in which they are returned by getResources()).

  • Check for the existence of a context initialization parameter named javax.faces.CONFIG_FILES. If it exists, treat it as a comma-delimited list of context relative resource paths (starting with a “/”), and load each of the specfied [sic] resources.

  • Check for the existence of a web application configuration resource named "/WEB-INF/faces-config.xml", and load it if the resource exists.

If you read through these 3 options, it appears that the 3rd option is the default in our new JDeveloper JSF application. So do the two other options provide us a means to segment our faces-config.xml file?

Option 1 and option 2 don't read particularly well. Maybe to somebody with more J2EE web experience or an interest in reading specifications this isn't double Dutch. As such it's time to find a more readable resource to assist us. The point to be made above though is that the JSF specification can be a useful place for finding out more about the workings of JSF in general.

Currently to my knowledge there are 4 texts that cover the JSF framework:

These books are a tad out of date but give a reasonable base to start with. Of the four books none of them are the golden JSF chalice, but collectively they help nut out JSF concepts and issues.

(Note there are other recent texts available on JSF component building that are less relevant to the discussion at hand, useful for understanding the component architecture and creating new components, but less about the plumbing's of JSF)

Mastering JavaServer Faces in chapter 4 under Configuring a Web Application for JSF - JSF Application Configuration files gives a better understanding of the 3 faces-config.xml options explained above.

For option 1 it states that all JSF implementations will "Look for a resource named /META-INF/faces-config.xml in every JAR resource that is located in the /WEB-INF/lib directory of the Web application. If such a resource exists, the configuration file is loaded at application startup."

This makes sense over the JSF specification, allowing additional JAR files to include their own faces-config.xml file. Great to know but not useful in our case as we want multiple files in our single application.

For option 2 Mastering JavaServer Faces says a JSF implementation will next "look for a context initialization parameter named javax.faces.application.CONFIG_FILES in the web.xml file for one or more JSF configurations that should be loaded. The value of this parameter is a comma delimited list of context relative resource paths (each starting with /). This particular method is useful when you wish to split up a large JSF application into manageable pieces."

Bingo! Exactly what we're looking for. The text then goes onto suggest on how to do this in your web.xml file with the following example:

<context-param>
    <param-name>javax.faces.application.CONFIG_FILES</param-name>
        <param-value>
            /WEB-INF/faces-config1.xml,
            /WEB-INF/faces-config2.xml
    </param-value>
</context-param>


Finally the text suggests that option 3 is ignored if option 2 is specified.

This raises some interesting questions and is worthy of a number of tests in JDeveloper which we'll do next

Does JDeveloper support multiple faces-config.xml files?

In answer to the first it becomes fairly obvious that JDeveloper does support multiple faces-config.xml files, as invoking the New Gallery under an existing JSF ViewController project, selecting the Web-Tier -> JSF -> JSF Page Flow & Configuration (faces-config.xml) option pops up the Create JSF Configuration Flow dialog. This dialog allows you to specify the new faces-config.xml file name, the directory name to place it under, and to include an entry in the web.xml file.


Accepting the defaults creates a new file faces-config.xml and an entry in the web.xml file as detailed in the Mastering JavaServer Faces text:

<context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>/WEB-INF/faces-config1.xml</param-value>
</context-param>


You'll note the param-name is different from the Mastering JavaServer Faces entry. We'll assume the JDeveloper entry is correct.

Further to this JDeveloper has out of the box support for multiple faces-config.xml files. One way to open the faces-config.xml file for a JSF ViewController project is to right-click the ViewController project and select the Open JSF Navigation menu option. With multiple faces-config.xml file, this option becomes a submenu with all faces-config.xml files listed allowing you to select the particular file you wish to edit:


JDeveloper then supports the standard Diagram, Overview, Source and History views on each file. Behind the scenes for the Diagram, JDeveloper maintains a diagram file matching the name of the faces-config.xml file with an extension of oxd_faces (eg. faces-config1.oxd_faces). The oxd_faces file stores the visual diagram elements that JDeveloper allows the developer to maintain on top of the faces-config.xml file. I'm guessing that outside of JDeveloper this file is superfluous but when modelling page navigation visually in JDeveloper it is required.

Does option 2 actually override option 3?

Let's now investigate if option 2 overrides option 3, or more specifically, if we include multiple faces-config.xml files as specified in the web.xml file, do they override the original single faces-config.xml file within the WEB-INF directory?

The easiest manner to test this is to create a simple JSF web page that reference a JSF managed bean property. The simple JSF web page contains the following form:

<h:form>
    <h:inputText value="#{myBean.value}"/>
</h:form>


The bean looks like this:

public class MyBean {

    String value = "MyBean";

    public MyBean() {
        System.out.println("MyBean instantiated");
    }

    public void setValue(String value) { this.value = value; }

    public String getValue() { return value; }
}


And the entry to manage the bean within the option 3 stand alone faces-config.xml file like this:

<managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>MyBean</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>


On running the application we discover the assumption is incorrect. The <h:inputText> tag's value should be empty if the stand alone faces-config.xml file is not referenced. Instead we see it has the default value "MyBean" extracted from the bean, as well as the message "MyBean instantiated" is printed to the console.

Hmmm, could it be option 2's 2nd faces-config file, namely faces-config1.xml is ignored? Let's extend our example. The web page now contains:

<h:form>
    <h:inputText value="#{myBean.value}"/>
    <h:inputText value="#{myBean2.value}"/>
</h:form>


A new managed bean looks like this:

public class MyBean2 {

    String value = "MyBean2";

    public MyBean2() {
        System.out.println("MyBean2 instantiated");
    }

    public void setValue(String value) { this.value = value; }

     public String getValue() { return value; }
}


... and in the 2nd faces-config1.xml file we include the following managed bean entry:

<managed-bean>
    <managed-bean-name>myBean2</managed-bean-name>
    <managed-bean-class>MyBean2</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>


A quick test shows that now both <h:inputText> tags have a value at runtime. This proves all faces-config.xml files are referenced regardless. Useful to know and test.

Which order are multiple faces-config.xml files read in?

Given that we have multiple faces-config.xml files, we need to check what order the files are read in. Consider the following scenario:


We have 2 faces-config.xml files, the default faces-config.xml that says page1 shall navigate to page2 on the navigation rule "success". In turn the 2nd file, faces-config1.xml says that page1 shall navigate to page3 on the navigation rule "success".

So which is it? A quick test reveals at runtime that page1 navigates to page2, thus the original faces-config.xml file is read first.

Are there any issues reported for multiple faces-config.xml files in JDeveloper?

Before I recommend a feature I like to do a search on Oracle's OTN JDeveloper forum to see if there are any issues. The issues can be a little hard to find yourself because they can require a production system with multiple users to replicate. Sharing in other users' experiences can assist the issues that may be encountered.

Some issues I found:



Summary on multiple faces-config.xml files

By default JDeveloper creates a faces-config.xml file in the WEB-INF directory of the ViewController project.

Additional faces-config.xml files can be created for a project via the Create JSF Configuration Flow dialog under the New Gallery -> Web-Tier -> JSF options.

Additional faces-config.xml files are specified within the web.xml file.

If present, the WEB-INF faces-config.xml file is read first at runtime, followed by additional faces-config.xml files specified in the web.xml file.

Additional faces-config.xml files allow the logical composition of entries into separate files. For example all navigation rules could be put in one file, managed beans in another, or alternatively all elements for a sub-system such as HR in one faces-config.xml file, the elements for another sub-system such as payroll in another faces-config.xml file.

Recommendations on JSF research

Once you're comfortable with building simple JSF application, expand your reading to include looking at the JSF specification, and review each time a new specification becomes available. Also grab a text on the JSF framework, read from back to front, and then review as your understanding increases.

You'll be surprised how much you pick up on a second or third read of a text. For the JDeveloper developers among us, Oracle's Steve Muench's articles are a key example. Start developing with JDeveloper ADF Business Components and try to understand Steve's scalability papers and you'll be left scratching your head. Give it another 6 months development and a revisit to the article and the penny will drop in most cases.

Frequent the forums and blogs beyond just Oracle's. ADF Faces and JDeveloper are just one set of tools that implement JSF. There are plenty of other forums out there who cover the same topics.

Test test test. Don't trust the documentation and don't trust this post. Don't base design decisions on documentation unless you've tested the theory.

As usual after this research, I discovered beyond the JSF specification and the books listed above, that's JDeveloper's documentation has a good section on this entitled "What you may need to know about multiple JSF configuration files" found here.

I don't know why but I always seem to refer to the JDeveloper documentation last, and am pleasantly surprised to find a section on my research topic.


Finally ..... I'm sure others will have had interesting experiences with multiple faces-config.xml files so it would be great if you could share the issues you've discovered, if not here, maybe on the JDeveloper OTN forum.

10 comments:

Cali said...

Chris,
Excelent starting point.
Let's go to the tests.
Thank you and best regards.
Carlos
POA/RS/BR

Chris Muir said...

Thanks for the compliment Carlos. Good luck with your faces-config.xml endeavours.

Regards,

CM.

Anonymous said...

Hi Chris,

Thanks for the Information!

Did a little more research into 10.1.3... and I found a section in the Oracle manuals regarding navigation conflicts.

Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01

16.2.4.3
http://download-east.oracle.com/docs/html/B25947_01/web_pagenavigation002.htm

It looks like the last loaded faces-config.xml file, or the last entry in a faces-config.xml file ends up becoming your navigation rule. Hence the behavior you describe regarding the WEB-INF/faces-config.xml.




Kenton

Chris Muir said...

No worries and thanks for the follow-up Kenton. Nice to see this functionality is documented somewhere.

Cheers,

CM.

Unknown said...

nice article. Another thing you could check is the order in which faces-config1.xml and faces-config2.xml are loaded. Thanks!

Unknown said...

"I don't know why but I always seem to refer to the JDeveloper documentation last, and am pleasantly surprised to find a section on my research topic."

Hahaha! I thought I was the only this happened to! There are moments I felt like I wasted hours (sometimes days) figuring it out on my own, when I could've gotten the answer in a few minutes if I knew where to look in the doco. Then again, I might not have understood or appreciated the doco completely until I learned it the hard way.

Cheers!

Rey

camus said...

Thanks for the information. =D

Nir Levy said...

Thank you for the research.

Hendy said...

You misspelled:

"For option 2 Mastering JavaServer Faces says a JSF implementation will next "look for a context initialization parameter named javax.faces.application.CONFIG_FILES in the web.xml file for one or more JSF configurations that should be loaded."

and also the example code, should be:

... javax.faces.CONFIG_FILES ...

Chris Muir said...

Thanks for the update, a rather old blog post on my part.

In looking around the internet I can see examples like yours, and like the one I've put forward. I can't comment with any expertise on why the difference occurs now as this was such a long time ago for me, but could it be a JSF specification change?

In turn checking back at my copy of "Mastering JavaServer Faces" it does in fact say javax.faces.application.CONFIG_FILES, so I didn't just make it up.

As such I'll leave readers to work out what works or not for them.

CM.