JNDI searches

T

Tim Slattery

We run our JEE web apps in BEA (now Oracle) Weblogic. We've from time
to time explored alternatives. Generally moving a WAR to another
platform works fine, with one exception....

We have a JNDI data source defined in the container, say "myData". To
use it, we make a call like:

InitialContext ic = new InitialContext();
DataSource datasource = (DataSource) ic.lookup("myData");

In Weblogic this works just fine, and I can use the datasource to
access the DB. But when we tried JBoss, I had to search for
"java:/myData". And when I run the app in Tomcat, I have to use
"java:/comp/env/jdbc/myData".

So to move my app to another container, I have to recompile and
remake the WAR.

This seems completely nuts to me. Am I missing a way around this, or
am I doomed to recompile and/or add searches on more and more variants
of the JNDI name?
 
J

Jean-Baptiste Nizet

Tim Slattery a écrit :
We run our JEE web apps in BEA (now Oracle) Weblogic. We've from time
to time explored alternatives. Generally moving a WAR to another
platform works fine, with one exception....

We have a JNDI data source defined in the container, say "myData". To
use it, we make a call like:

InitialContext ic = new InitialContext();
DataSource datasource = (DataSource) ic.lookup("myData");

In Weblogic this works just fine, and I can use the datasource to
access the DB. But when we tried JBoss, I had to search for
"java:/myData". And when I run the app in Tomcat, I have to use
"java:/comp/env/jdbc/myData".

So to move my app to another container, I have to recompile and
remake the WAR.

This seems completely nuts to me. Am I missing a way around this, or
am I doomed to recompile and/or add searches on more and more variants
of the JNDI name?

The standard way is to define a resource-ref in your web.xml file. By
convention, resource-refs for JDBC datasources are defined in the jdbc
context. For example : jdbc/myDataSource. All the resource-refs defined
in we.xml are accessible via the java:comp/env/ context. In this case,
you would thus have to use
initialContext.lookup("java:comp/env/jdbc/EmployeeDB").
The name of the resource-ref is purely logical, and constitutes an
indirection for the real name of the dataSource in the app server. this
allows deploying two web-apps using a different logical name internally
for their dataSource, but effectively sharing a common physical
dataSource. Everything above is standard, and supported by every JEE
appserver.

The mapping between the logical name of the resource-ref and the
physical dataSource is where the standard doesn't say anything. It
depends on the appserver. In Tomcat, you have to declare a resource in
the context of the webapp (see
http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#JDBC Data Sources)
In WebLogic, you have to declare the link between the logical name and
the physical dataSource in the weblogic.xml proprietary descriptor. See
http://download.oracle.com/docs/cd/E15523_01/web.1111/e13712/weblogic_xml.htm#i1087465

Hope it helps.

JB.
 
T

Tom Anderson

We run our JEE web apps in BEA (now Oracle) Weblogic. We've from time
to time explored alternatives. Generally moving a WAR to another
platform works fine, with one exception....

We have a JNDI data source defined in the container, say "myData". To
use it, we make a call like:

InitialContext ic = new InitialContext();
DataSource datasource = (DataSource) ic.lookup("myData");

In Weblogic this works just fine, and I can use the datasource to
access the DB. But when we tried JBoss, I had to search for
"java:/myData". And when I run the app in Tomcat, I have to use
"java:/comp/env/jdbc/myData".

The Tomcat form is what the standard specifies. If you use that in
WebLogic and JBoss, does it work? It should. If so, you can use that
across the board.

If not, er, well, yes. Define a server-dependent JNDI name prefix and pass
it in as an env-entry or system property, perhaps?

tom
 
T

Tim Slattery

The Tomcat form is what the standard specifies. If you use that in
WebLogic and JBoss, does it work?

Don't know about JBoss (that was a while ago), but it does not work in
Weblogic.
If not, er, well, yes. Define a server-dependent JNDI name prefix and pass
it in as an env-entry or system property, perhaps?

No idea of that.
 
T

Tom Anderson

Don't know about JBoss (that was a while ago), but it does not work in
Weblogic.

Okay, having dug into this a bit, i think the rule is that java:comp/env
has to be visible *from a J2EE component*, which i suspect in practice
means from an EJB. It's basically a private environment area that
surrounds each component - each component actually has a *different*
comp/env. I would guess, then, that you're making your lookups from
outside a component - from code somewhere in the region of the servlets,
perhaps? In that case, there is no proper comp/env defined. Exactly where
in the JNDI namespace your resources are bound is, inexplicably, not
specified, and containers can do what they like. Tomcat makes it look the
same as if the lookup came from a component, WebLogic doesn't.

I haven't found a good solution for this. Most of the suggestions are
along the lines of this:
No idea of that.

public class JNDILookupHelper {
public static Object lookup(String name) throws some exceptions {
String prefix = System.getProperty("jndi.prefix", "");
String fullName = prefix + name;
InitialContext ic = new InitialContext();
return ic.lookup(fullName);
}
}

Then apply -Djndi.prefix= as needed.

tom
 
T

Tim Slattery

Tom Anderson said:
Okay, having dug into this a bit, i think the rule is that java:comp/env
has to be visible *from a J2EE component*, which i suspect in practice
means from an EJB. It's basically a private environment area that
surrounds each component - each component actually has a *different*
comp/env. I would guess, then, that you're making your lookups from
outside a component - from code somewhere in the region of the servlets,
perhaps?

Yes, a servlet. The app is based on Struts.
String prefix = System.getProperty("jndi.prefix", "");

This looked really good, but....there's no "jndi.prefix" property in
either Tomcat 6 or Weblogic 10, nor anything close (I listed them all
out).

According to
http://java.sun.com/javaee/5/docs/tutorial/doc/bncjk.html, I should be
able to do this using "Resource injection", but I can't make that work
in either server.
 
L

Lew

Tim said:
This looked really good, but....there's no "jndi.prefix" property in
either Tomcat 6 or Weblogic 10, nor anything close (I listed them all
out).

There is if you don't ignore tom's suggestion to define one:
Defining the variable to be read is a not-insignificant step.
According to
http://java.sun.com/javaee/5/docs/tutorial/doc/bncjk.html, I should be
able to do this using "Resource injection", but I can't make that work
in either server.

I've not been able to make resource / dependency injection work yet. I've
only tried it with GlassFish.
 
R

Roedy Green

This seems completely nuts to me. Am I missing a way around this, or
am I doomed to recompile and/or add searches on more and more variants
of the JNDI name?

Hold your nose for this one. It smells of very old C++ code.

Poke around in System.properties to see if you can find something that
will tell you which womb you are using. Then write a method that does
your JNDI given a magic string.

If there isn't anything, invent something. Possible tools:
System.properties, SET environment, hide something in the persistence
mechanism, loading a small XML config file, loading some
tweaking/customisation code via Class.forName.

This last one it what I use for my own static macros to load dozens of
custom parameters and custom methods in one fell swoop.
 
A

Abu Yahya

Roedy said:
Hold your nose for this one. It smells of very old C++ code.

Poke around in System.properties to see if you can find something that
will tell you which womb you are using. Then write a method that does
your JNDI given a magic string.

We had a similar problem, and went with a solution similar to what Roedy
suggests - finding out which womb we are in. We had to port our
application to Websphere and Tomcat. For Tomcat, we instantiate
InitialContext by calling the zero argument constructor, while in
WebSphere we need to pass a Properties object with a key-value pair of
Context.INITIAL_CONTEXT_FACTORY==>"com.ibm.websphere.naming.WsnInitialContextFactory"

So, here's what we did. We tried to get the initial context object using
the WebSphere method, but if that failed, we assumed we were in Tomcat
and called the zero argument constructor and attached the prefix.

Here's the relevant piece of code:

java.util.Properties parms = new java.util.Properties();

// Assume WebSphere
parms.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
try{
// Get initial context object
initCtx = new InitialContext(parms);
}catch(Exception c){
// Exception, so we are in Tomcat
initCtx = new InitialContext();
initCtx = (Context) initCtx.lookup("java:comp/env");
}
this.datasource = (DataSource) initCtx.lookup(dbDataSource);
 
T

Tom Anderson

We had a similar problem, and went with a solution similar to what Roedy
suggests - finding out which womb we are in. We had to port our
application to Websphere and Tomcat. For Tomcat, we instantiate
InitialContext by calling the zero argument constructor, while in
WebSphere we need to pass a Properties object with a key-value pair of
Context.INITIAL_CONTEXT_FACTORY==>"com.ibm.websphere.naming.WsnInitialContextFactory"

Really? Did you try setting the javax.naming.factory.initial system
property to that value at WebSphere startup, and then using the no-args
constructor?

tom
 
A

Abu Yahya

Tom said:
Really? Did you try setting the javax.naming.factory.initial system
property to that value at WebSphere startup, and then using the no-args
constructor?
I didn't know about that method previously - it certainly works :)

But setting the property as a JVM arg does not break the code I posted
above - that is, if you first test whether you're in Websphere rather
than in Tomcat.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,816
Latest member
SapanaCarpetStudio

Latest Threads

Top