Search code examples
javaspringtomcatweblogicjndi

Spring & JNDI: locate resource platform independent


I'm trying to load in a property file provided by JNDI which should be platform independent. I know I can do it in the following ways, dependent on the platform:

For Weblogic:

Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
InitialContext context = new InitialContext(properties);
context.lookup(propertiesLocation);

For Tomcat:

Context context = new InitialContext();
Context envCtx = (Context) context.lookup("java:comp/env");
final Object lookup = envCtx.lookup(propertiesLocation);

The core problem is that in Tomcat the prefix java:comp/env/ is needed. Since Spring is able to load all this platform independently, I tried looking into the possibilities of Spring loading my JNDI resources.

I found out I can use the JndiTemplate of Spring in the following way:

JndiTemplate jndiTemplate = new JndiTemplate();
Object lookup = jndiTemplate.lookup(propertiesLocation);

This is still platform dependent however, needing to use java:comp/env as a prefix during the lookup on tomcat. Looking further on StackOverflow and in the Spring javadocs, I found the class JndiLocatorSupport, which has the following:

JNDI names may or may not include the "java:comp/env/" prefix expected by J2EE applications when accessing a locally mapped (ENC - Environmental Naming Context) resource. If it doesn't, the "java:comp/env/" prefix will be prepended if the "resourceRef" property is true (the default is false) and no other scheme (e.g. "java:") is given.

So I created a JndiObjectFactoryBean which extends JndiLocatorSupport, enabled setResourceRef but it doesn't seem to append the prefix.

Core problem:
When using the following code:

JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
factoryBean.setResourceRef(true);
Object lookup = factoryBean.getJndiTemplate().lookup(propertiesLocation);

I'd expect it to have the same effect as:

JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
Object lookup = factoryBean.getJndiTemplate().lookup("java:comp/env/" + propertiesLocation);

But it doesn't. It seems to have no effect at all. But if I look through the source code, it does go like this: JndiObjectFactoryBean.lookup() -> JndiObjectLocator.lookup() -> JndiLocatorSupport.lookup(), which does call the right methods.


Solution

  • JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
    factoryBean.setResourceRef(true);
    Object lookup = factoryBean.getJndiTemplate().lookup(propertiesLocation);
    

    and

    JndiTemplate jndiTemplate = new JndiTemplate();
    Object lookup = jndiTemplate.lookup(propertiesLocation);
    

    Are the same with regards to the lookup. The first is only a very complex way to obtain a JndiTemplate. All the settings you do are for the JndiObjectFactoryBean NOT for the internal JndiTemplate. Basically your whole approach doesn't add anything.

    Instead use a JndiLocatorDelegate and let that do the lookup (don't try to get the JndiTemplate!).

    JndiLocatorDelegate jndi = JndiLocatorDelegate.createDefaultResourceRefLocator();
    Object lookup = jndi.lookup(propertiesLocation);
    

    This will by default do a lookup in java:comp/env and if not found do a fallback to a plain propertiesLocation (what you passed in).