JNDI resource lookups in WebSphere Application Server

By Stefan Gybas | 20 September 2013

The Java Naming and Directory Interface (JNDI) is mainly used for accessing resources that are managed by a container. JEE application servers expose JDBC data sources, JMS connection factories, JTA user transactions among others to applications via JNDI. Each resource has a global unique JNDI name. For example jdbc/ORA45X2 could be a data source.

Section EE.5.2 of the JEE 7 specification says that application components should not lookup resources using the global JNDI name but use a local JNDI naming context instead. For example, the name space java:comp provides a local context per application component. Each EJB is a component but for compatibility reasons all components in a web module share the same context. The other name spaces java:module, java:app and java:global are usually not used when an application contains only a web module, for example when EJBs are not used.

Resource references are created as environment entries in the java:comp/env/ name space. They provide a layer of indirection and get mapped to JNDI names during deployment. This is either done by the deployer or using a container-specific deployment descriptor that is shipped by the application. In this example java:comp/env/jdbc/customer_db is mapped to jdbc/ORA45S2.

WebSphere Application Server logs a J2CA0294W warning in debug mode, if a direct JNDI lookup is done.

For web applications, resource references must be defined in WEB-INF/web.xml:

<web-app id="example" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="[...]">

  <resource-ref>
    <description>Customer master data</description>
    <res-ref-name>jdbc/customer_db</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>

Application code then has to look up java:comp/env/jdbc/customer_db like this:

InitialContext context = new InitialContext();
DataSource customerDataSource = (DataSource) context.lookup(
    "java:comp/env/jdbc/customer_db");

The Spring Framework 3.0 helps you with JNDI lookups. You can use <jee:jndi-lookup> in your application context:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="[...]">

  <jee:jndi-lookup id="customerDataSource"
    jndi-name="jdbc/customer_db"
    expected-type="javax.sql.DataSource" />
</beans>

Spring prepends the java:comp/env/ name space when it’s not already present and the resource-ref attribute is not set to false. It falls back to the global JNDI name if the resource is not found in the local context so you should not use the java:comp/env/ prefix for a JNDI lookup with Spring.

The deployment descriptor for a Servlet 2.5 application on WAS 7 and above is WEB-INF/ibm-web-bnd.xml. You can specify the bindings from local environment entries to global JNDI names so the deployer doesn’t have to.

<web-bnd version="1.0"
    xmlns="http://websphere.ibm.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="[...]">

  <virtual-host name="default_host" />
  <resource-ref name="jdbc/customer_db"
    binding-name="jdbc/ORA45X2" />
</web-bnd>

For a JTA UserTransaction, the name java:comp/UserTransaction must be used. There’s no global JNDI name for the user transaction since the local transaction context is required. For this reasons, unmanaged threads without a JEE context can not participate in a container-managed transaction.

Category: Java | Tags: WAS, Spring