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

For more information, please explore the Attic.

Shale JNDI Integration

JNDI Introduction

The Java Naming and Directory Interface (JNDI) API is commonly used in a Java2 Enterprise Edition (J2EE) (recently renamed to Java Enterprise Edition (Java EE)) to acquire references to resources that are declared in either:

  • The deployment descriptor (web.xml) provided with the application.
  • The customized configuration settings applied when the application is depoyed to a particular instance of a particular application server.
As an example of the usefulness of this technique, consider an application that requires a JDBC data source (i.e. a connection pool). Consider also that the development environment contains two instances of the database (development and staging), in addition to the production instance. If your application can define just a reference to the data source, then the same web application archive (WAR) can be deployed, unchanged, to any of these instances. The hookup to a particular database instance is performed through deployment configuration, rather than modifying property settings in the WAR for each environment.

Services Provided

Shale includes custom instances of the VariableResolver and PropertyResolver APIs, from JavaServer Faces, that allow value binding and method binding expressions to navigate through the JNDI InitialContext (and subcontexts) that are provided to each web application by the application server. Such expressions can be used to configure the values for properties of a JSF component, in the usual way. In addition, expressions can be evaluated programatically in your event handling code -- providing an easier to use mechanism for acquiring such resources.

For example, assume you have a data source (i.e. instance of javax.sql.DataSoruce) with a resource reference name of jdbc/CustomerDB defined in your deployment descriptor. You can programmatically gain access to this data source by evaluating the following expression:

#{jndi['jdbc/CustomerDB']}

Using JNDI Integration

Two examples of using the JNDI integration capabilities are presented -- one using a value binding to a JSF component property, and one using programmatic access to acquire a resource.

(1) Binding to JSF Component Property

JNDI supports the concept of environment entries that can be declared in the deployment descriptor, and optionally modified by the deployment configuration when the application is installed in a particular environment. Let's assume that you have a boolean environment entry to define whether your application is running in debug mode or not, declared in web.xml like this:

<env-entry>
  <description>Flag indicating whether we run in debug mode.</description>
  <env-entry-name>debugMode</env-entry-name>
  <env-entry-value>false</env-entry-value>
  <env-entry-type>java.lang.Boolean<env-entry-type>
</env-entry>

Now, assume you have a status message that you only want to have displayed when debug mode is enabled. You can bind the rendered property of the component to this environment entry value:

<h:outputText ... rendered="#{jndi.debugMode}" .../>

(2) Programmatic Resource Access

Assume you have a data source reference (discussed in the introduction) defined in your web.xml like this:

<resource-ref>
  <description>Customer Database</description>
  <res-ref-name>jdbc/CustomerDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

You can acquire a java.sql.Connection from this data source with code like the following (note that the convenience base class BaseViewController contains a getBean() method that substantially reduces the amount of code needed):

FacesContext context = FacesContext.getCurrentInstance();
ValueBinding vb =
  context.getApplication().createValueBinding("#{jndi['jdbc/CustomerDB'].connection}");
Connection conn = (Connection) vb.getValue(context);

This works by first retrieving the JNDI-configured data source instance, and then calling its getConnection() method. After you are through with the connection, return it to the pool by calling the connection's close() method.