Announcement Announcement Module
No announcement yet.
External Properties for Tomcat Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • External Properties for Tomcat

    I would like to have properties files loaded based on various contexts (dev, cm, prod) as well as from different locations (inside an archive (jar or war), from a directory specified by an environmental variable, from a directory specified via a JNDI lookup). So far I've been successful loading properties from the archive and via a path specified by an environmental variable if I'm running as a stand-alone Java application. However, when I'm running in Tomcat, I can only load properties files from the archive. Environmental variables don't work (and I'd been told to expect that), but I can't get JNDI lookups to work either. The JNDI variables are getting set correctly. I've printed them out in a JSP to prove it. It just seems like Spring is not able to interpolate them correctly in the SPEL in my application context. Below are the relevant snippets of configuration.

    This what I put in my TOMCAT_HOME/conf/context.xml file:
    <Environment name="MYCONFIGURABLETOMCATAPP_HOME" value="C:\temp" type="java.lang.String"/>
    <Environment name="RUNTIME_ENV" value="dev" type="java.lang.String"/>
    This is what I have in my application context:

    <!-- Directory where properties files will live. -->
       <jee:jndi-lookup id="jndiMyConfigurableTomcatAppHome" jndi-name="java:comp/env/MYCONFIGURABLETOMCATAPP_HOME" expected-type="java.lang.String" />
    <!-- Runtime environment. Let's the property file be named,, etc. -->
       <jee:jndi-lookup id="jndiRuntimeEnv" jndi-name="java:comp/env/RUNTIME_ENV" expected-type="java.lang.String"/>
        <!-- Properties from Environmental Variables - used outside of servlet container only -->
    	<context:property-placeholder location="file:///#{ systemProperties['MYCONFIGURABLETOMCATAPP_HOME'] }/conf/database-#{ systemProperties['RUNTIME_ENV'] }.properties"
    		ignore-unresolvable="true" ignore-resource-not-found="true"/>
    	<!-- Properties from JNDI - used within servlet container only -->
    	<context:property-placeholder location="file:///#{ jndiMyConfigurableTomcatAppHome }/conf/database-#{ jndiRuntimeEnv }.properties"
    		ignore-unresolvable="true" ignore-resource-not-found="true"/>
        <!--  Properties from classpath / WAR file - used in any context -->
    	<context:property-placeholder location="classpath:/"
    		ignore-unresolvable="true" ignore-resource-not-found="true"/>
    	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
    The goals is that it uses JNDI variables to resolve the property files if they are available (which is when itís running in Tomcat). It uses the environmental variables if they are available (when itís running as a stand-alone Java application). And it uses the properties files in the JAR/WAR file if the others are not found. All of that works fine except the JNDI properties.

    How can I get Spring to use the JNDI properties when loading properties files in the application context?

    Joshua Smith

  • #2
    I've done some additional searching, but am still coming up short. There are multiple references that talk about using JNDI in the applicationContext.xml file and a number of references that talk about using property-placeholders, but I can't seem to find anything that combines the two such that the value retrieved via a JNDI look-up can be used in the Spring Expression Language (SPEL) used with a property-placeholder. Can anyone point me to some related references or examples?

    Joshua Smith


    • #3
      I think I've figured out what's going on, but I'm not totally sure about how to fix it.

      The property-placeholders implement BeanFactoryPostProcessor. These get called VERY early in the lifecycle.

      The jndi-lookup element is just a standard bean.

      I think the property-placeholders are firing before the jndi-lookup and, as a result, the interpolation can't take place to include the values obtained via JNDI lookup.

      So I think what I need is a custom BeanFactoryPostProcessor that does exactly what JndiObjectFactory bean does, but during the BeanFactoryPostProcessor phase of the lifecycle.

      Messing with the lifecycle provokes lots of questions. Will the things I need to do the JNDI lookup already be initialized during the BeanFactoryPostProcessor phase? Can I just extend JndiObjectFactory and implement BeanFactoryPostProcessor to get what I need?

      I'd appreciate input from anyone that has focused on these sorts of lifecyle things. What is the best way to tackle this?

      Joshua Smith