23 June 2006

DataSource lookup using java:comp/env

Helped someone out this week where the claim was OC4J doesn't support the same standards they are used to developing with on Tomcat.

The reported problem was that the developer was trying to lookup a DataSource using the standard ENC approach -- java:comp/env/jdbc/DataSource from within a Servlet.

"It doesn't work with OC4J, I must change all my code to lookup the datasource using its actual name!"

OK, lets take a look at it -- that's not quite true.

Yes, we do enable a direct datasource lookup to be done using just the jndiLocation value of the DataSource in need. For example, if there is an actual physical datasource defined on the J2EE container with a location of "jdbc/OracleDS" then it can be looked up using the actual name:
  DataSource ds = (DataSource)ic.lookup("jdbc/OracleDS");

But this is a convenience mechanism only. It's not something I'd recommend or use other than for something quick and dirty. It hardcodes the application code so that it requires a physical datasource to be defined on the J2EE container.

If I was developing I'd opt for the standard, portable approach so that the application makes no assumptions about its target environments.

Which basically means using the ENC (Environment Naming Context) model which is implemented by J2EE servers to abstract application resources away from their physical manifestations. I've always wanted to use that word somewhere ...

To use the ENC model you need to do two things.

1. Do the Logical

In the application, you define a logical representation of the resources you need to use. This is done using resource-ref definitions in the standard J2EE deployment descriptor files. Whenever you need to get hold of the resource, you look it up from the JNDI ENC and use it.

This means the application is free from using anything specific to a physical environment in the code. So it becomes portable.

Here's an example. Lets say I have a Servlet which needs to connect to a database and execute a query. I want the Servlet to be portable so it can be deployed anywhere.

What I do is to first define a resource-ref element in the web.xml file which identifes the logical datasource name to be used:
  <resource-ref>
<res-auth>Container</res-auth>
<res-ref-name>bing/Bang</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>

This says to the J2EE container when the app is deployed that a DataSource should be mapped to the jndiLocation "bing/Bang".

To get hold of this DataSource in the Servlet code, it is looked up like this:
  InitialContext ic = new InitialContext();
DataSource bingBang = (DataSource)ic.lookup("java:comp/env/bing/Bang");
Connection con = bingBang.getConnection();
...

OK -- all standards stuff. Note the use of the java:comp/env prefix here when looking up the resource. This is needed because resource-ref declarations are bound by the J2EE container into the ENC and this java:comp/env is the way to reach into the ENC.

But how does this logical "bing/Bang" actually get married up to a database to connect to?

2. Do the Physical

A physical datasource is configured at the J2EE container with details such as which database to connect to, the username password combination and any other special properties. It is given a unique name so it can be identified and used -- for example "jdbc/MyXEDatabase"

Once the application has been packaged, its time for deployment. And its at deployment time that the person doing the deployment makes the decision on how to map the logical resource-ref entries to their physical counterparts on the server.

What this means in this specific case during the deployment process, the deployment manager will extract the list of logical references it finds in the standard deployment descriptors (DataSource - bing/Bang) and allow you to specify which of the physical datasources it should be be mapped to -- in this case "jdbc/MyXEDatabase".

This gets automatically generated into a deployment descriptor which is read by OC4J:
  <orion-web-app>
<resource-ref-mapping location="bing/Bang" name="jdbc/MyXEDatabase"/>
</orion-web-app>

So that when an application looks up bing/Bang it really gets given jdbc/MyXEDatabase

And there you have it.

3 comments:

Daniel K said...

Unfortunately, this doesn't appear to work. I've tried do EXACTLY what you've suggested, and it always fails to not find the data source. I can only get this to work with a direct reference to the ejb-location attribute of my data-source element, and without using java:/comp/env/.

I'm using OC4J 10.1.2.0.2. My data-sources definition is in the data-sources.xml file in the config directory, and the orion-web.xml file was placed with my web.xml file and extracted on deployment.

Anonymous said...

The orion-web.xml its actually that bing/Bang is the name, and not the location. Its backwards in the article.

Anonymous said...

The problem is that the name and location attribute values were reversed in the author's example. If you switch them around it should work:

... name="bing/Bang" location="jdbc/MyXEDatabase" ...