JNDI path Tomcat vs. Jboss

I have DataSource which is configured on Tomcat 6 in context.xml as MyDataSource. And I'm fetching it the following way:

      DataSource dataSource;
            try {
                dataSource = (DataSource) new InitialContext().lookup("java:comp/env/MyDataSource");
            } catch (NamingException e) {
                throw new DaoConfigurationException(
                    "DataSource '" + url + "' is missing in JNDI.", e);
            }

Everything works fine. Now I'm exporting this code to Jboss AP 6. and I configured my dataSource and its connection pool as local-tx dataSource under the same name.

When I'm executing the code above, I'm getting NamingException exception. after some investigation I've found that correct way to call my DataSource under Jboss is

 dataSource = (DataSource) new InitialContext().lookup("java:/MyDataSource");

Can anybody explain me why should I omit "comp/env" in my JNDI path under Jboss?


Solution 1:

The portable approach for defining data sources is to use a resource reference. Resource references enable you to define the JNDI name for your data source, relative to your application naming context (java:comp/env), and then map that logical reference to the physical resource defined in the application server, whose JNDI name is proprietary to the application server vendor. This approach enables your code and assembly to be portable to any compliant application server.

Step 1: Declare and Lookup Resource Reference

Option 1

This can be done by declaring a resource-ref in your web deployment descriptor (WEB-INF/web.xml):

<resource-ref>
    <description>My Data Source.</description>
    <res-ref-name>jdbc/MyDataSource</res-ref-name> 
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

Within your code, you can then lookup this resource using the JNDI name java:comp/env/jdbc/MyDataSource:

dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/MyDataSource");

This JNDI name will not change regardless of the server where the application is deployed.

Option 2

Alternatively, starting in Java EE 5 (Servlet 2.5), this can be done even easier within your code using the @Resource annotation. This eliminates the need for configuring the resource-ref in your web deployment descriptor (web.xml) and prevents the need to perform an explicit JNDI lookup:

public class MyServlet extends HttpServlet {

    @Resource(name = "jdbc/MyDataSource")
    private DataSource dataSource;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // dataSource may be accessed directly here since the container will automatically
        // inject an instance of the data source when the servlet is initialized

}

This approach has the same results as the previous option, but cuts down on the boilerplate code and configuration in your assembly.

Step 2: Map Resource Reference to Data Source

Then, you will need to use your application server's proprietary approach for mapping the resource reference to the physical data source that you created on the server, for example, using JBoss's custom deployment descriptors (WEB-INF/jboss-web.xml):

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <resource-ref>
        <res-ref-name>jdbc/MyDataSource</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <jndi-name>java:/MyDataSource</jndi-name>
    </resource-ref>
</jboss-web>

Or, for example, using Tomcat's context.xml:

<Resource name="jdbc/MyDataSource" . . . />

Solution 2:

You can add to your data source definition the 'jndi-name' tag:

jndi-name - the JNDI name under which the DataSource should be bound.

You can find data source documentation on JBoss wiki: ConfigDataSources