Thursday, December 13, 2012

Setting JSF ProjectStage with JNDI

One nice feature of JSF2 is the ProjectStage setting.  It lets the JSF implementation and the application developer optimize and customize behavior based on whether JSF is running in Development, Production, SystemTest, or UnitTest.  The usual way to tell JSF about which ProjectStage to use is through a context param in web.xml.
<context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
</context-param>
But you would rather not muck with web.xml for something like this.  It's much cleaner to define your ProjectStage based on what kind of server environment you are running.  In other words, wouldn't it be nice if JSF could know whether your server is running in Development, Test, Production, etc?  Then you wouldn't need to change your application at all.

A little-known but handy feature of JSF2 is the ability to use JNDI to set the JSF ProjectStage.  Here is how you do that in JBoss AS7.

First, add a resource reference in web.xml.
<resource-ref>
   <res-ref-name>jsf/ProjectStage</res-ref-name>
   <res-type>java.lang.String</res-type>
</resource-ref>
Then, create a jboss-web.xml file and place it beside web.xml in your WEB-INF directory. The file should bind the resource reference to JNDI like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<jboss-web>
    <resource-ref>
        <res-ref-name>jsf/ProjectStage</res-ref-name>
        <res-type>java.lang.String</res-type>
        <jndi-name>java:/env/jsf/ProjectStage</jndi-name>
    </resource-ref>
</jboss-web> 
Next, add the JNDI value to JBoss AS7 in the naming subsystem of your configuration file, such as standalone.xml:
      <subsystem xmlns="urn:jboss:domain:naming:1.1">
            <bindings>
                <simple name="java:/env/jsf/ProjectStage" value="Development"/>
            </bindings>
        </subsystem>

You can also add the JNDI value using CLI:
/subsystem=naming/binding=java\:\/env\/jsf\/ProjectStage/:add(binding-type=simple,value=Development,class=java.lang.String)
But I like to use CLI GUI for this because it automatically handles the escape characters:

Now we are done, but you might also want to change the value of ProjectStage on your server. Again, you can do that in XML or you can use CLI: 
/subsystem=naming/binding=java\:\/env\/jsf\/ProjectStage/:write-attribute(name=value,value=UnitTest)