Announcement Announcement Module
Collapse
No announcement yet.
Tomcat, war files and PropertyPlaceholderConfigurer Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Tomcat, war files and PropertyPlaceholderConfigurer

    Hi,
    I'm looking for a way to keep my property files outside the war file of my application. So far I've put those property files in the web application itself, and referred to them by the classpath.
    Yet, I'd prefer to keep them out so that I don't need to unpack/change/repack the war file every time I deploy the application to a different database/ip/database user/so on.

    How do you solve this problem (in particular, using Tomcat as the web container?)

    Best regards
    Andrea Aime

  • #2
    I'm looking for a way to keep my property files outside the war file of my application
    Which properties? If it's PropertyPlaceholderConfigurer, you can use something like:
    <property name="location"><value>file:/temp/jdbc.properties</value></property>

    so that I don't need to unpack/change/repack the war file every time I deploy the application
    Usually you can pretty much automate this - loading different properties for different environments so it isn't much of a hassle. It can also be version controlled which is generally safer.

    Comment


    • #3
      Originally posted by katentim
      I'm looking for a way to keep my property files outside the war file of my application
      Which properties? If it's PropertyPlaceholderConfigurer, you can use something like:
      <property name="location"><value>file:/temp/jdbc.properties</value></property>
      That's a fixed location. Bad idea, my clients may want to redeploy the application on a different filesystem/operating system.

      so that I don't need to unpack/change/repack the war file every time I deploy the application
      Usually you can pretty much automate this - loading different properties for different environments so it isn't much of a hassle. It can also be version controlled which is generally safer.[/quote]

      Not that I can control this much... I would like to provide my client IT department with simple instructions on how to move the application, the database and so on.

      Comment


      • #4
        That's a fixed location. Bad idea, my clients may want to redeploy the application on a different filesystem/operating system.
        What about a simple install program to modify the WAR appropriately? Maybe a setup page on the WAR to edit some configuration parameters on installation?

        Comment


        • #5
          There was some discussion about JNDI based property placeholder last week. It could be an alternative for you. I don't remember which forum it was now though - either this or "Web".

          Comment


          • #6
            Well, so far I've put a property file with the same name as the application in tomcat/shared/classes. It's easy to modify, and should not conflict with other applications (and I don't need to write an application to modify the war file)
            Yet, I'd prefer a solution where only my application sees that file...

            Comment


            • #7
              Solution I used is to simply omit a path and put the file in the current folder. Also, putting the file on the server classpath is is a good solution (tomcat/common/classes).

              Comment


              • #8
                In order to keep my configurations somewhat container- and OS-independent, I use a combination of a JNDI environment variable and a PropertyPlaceholderConfigurer to load and apply configuration information. Under Tomcat, here's how it works.

                First, in the application's context.xml, I define a resource string containing the path to the configuration file:

                Code:
                    <Context ...>
                        <!-- Location of the deployment configuration file -->
                        <Environment name="config/configurationPath" 
                                type="java.lang.String"
                                value="file&#58;C&#58;\path\to\config.properties" />
                     ...
                    </Context>
                Then in my Spring bean files, I extract the value from JNDI and define and configure the PropertyPlaceholderConfigurer as such:

                Code:
                    <beans ...>
                
                        <!-- Import deployment configuration file path from JNDI -->
                        <bean id="configurationPath"
                                class="org.springframework.jndi.JndiObjectFactoryBean">
                            <property name="jndiName">
                                <value>java&#58;comp/env/config/configurationPath</value>
                            </property>
                        </bean>
                
                        <!-- Load our substitution properties into a Properties object. -->
                        <bean id="configurationProperties"
                                class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                            <property name="locations">
                                <ref bean="configurationPath" />
                            </property>
                        </bean>
                
                        <!-- Property configurer for pulling property settings from
                                applicationContext.properties -->
                        <bean id="propertyPlaceholderConfigurer"
                                class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                            <property name="properties">
                                <ref bean="configurationProperties" />
                            </property>
                        </bean>
                    ...
                    </beans>
                Obviously, this can be simplified and collapsed into fewer bean definitions as you desire. I used 3 separate definitions in the project from which this example was extracted, but the reasons for that are unrelated to this thread.

                This scheme allows the deployer to move the configuration file to any location that can be specified via a Spring resource string. WARs need not be unpacked (though unpacking them doesn't hurt either.) With a few minor changes, you could also cause the configuration to default back to an in-WAR 'classpath:' configuration file if you so desired.

                I apologize if I'm not answering the correct question here. Always a possibility. :-)

                Comment


                • #9
                  You could use a subclass of PropertyPlaceHolderConfigurer that resolves placeholders as environment entry:

                  Code:
                  package org.sprfr;
                  
                  import java.util.Properties;
                  
                  import javax.naming.NamingException;
                  
                  import org.springframework.beans.factory.InitializingBean;
                  import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
                  import org.springframework.jndi.JndiTemplate;
                  
                  public class EnvEntryPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements InitializingBean &#123;
                  
                  	public static String CONTAINER_PREFIX = "java&#58;comp/env/";
                  
                  	private boolean resourceRef = true;
                  
                  	public void setResourceRef&#40;boolean resourceRef&#41; &#123;
                  		this.resourceRef = resourceRef;
                  	&#125;
                  
                  	public boolean isResourceRef&#40;&#41; &#123;
                  		return resourceRef;
                  	&#125;
                  
                  	private boolean envEntryOverride = false;
                  
                  	private JndiTemplate jndiTemplate;
                  
                  	public void setEnvEntryOverride&#40;boolean contextOverride&#41; &#123;
                  		this.envEntryOverride = contextOverride;
                  	&#125;
                  
                  	public void afterPropertiesSet&#40;&#41; throws Exception &#123;
                  		this.jndiTemplate = new JndiTemplate&#40;&#41;;
                  	&#125;
                  
                  	protected String resolvePlaceholder&#40;String placeholder, Properties props&#41; &#123;
                  		String value = null;
                  		if &#40;this.envEntryOverride&#41; &#123;
                  			value = resolveEnvEntryPlaceholder&#40;placeholder&#41;;
                  		&#125;
                  		if &#40;value == null&#41; &#123;
                  			value = super.resolvePlaceholder&#40;placeholder, props&#41;;
                  		&#125;
                  		if &#40;value == null&#41; &#123;
                  			value = resolveEnvEntryPlaceholder&#40;placeholder&#41;;
                  		&#125;
                  		return value;
                  	&#125;
                  
                  	protected String resolveEnvEntryPlaceholder&#40;String placeholder&#41; &#123;
                  		String value = null;
                  		Object envEntry = null;
                  		try &#123;
                  			String jndiNameToUse = convertJndiName&#40;placeholder&#41;;
                  			envEntry = jndiTemplate.lookup&#40;jndiNameToUse&#41;;
                  		&#125; catch &#40;NamingException e&#41; &#123;
                  			logger.error&#40;"Naming Exception while trying to lookup env entry " + placeholder, e&#41;;
                  		&#125;
                  		if &#40;envEntry != null&#41; &#123;
                  			value = envEntry.toString&#40;&#41;;
                  		&#125;
                  		return value;
                  	&#125;
                  
                  	protected String convertJndiName&#40;String jndiName&#41; &#123;
                  		if &#40;isResourceRef&#40;&#41; && !jndiName.startsWith&#40;CONTAINER_PREFIX&#41; && jndiName.indexOf&#40;'&#58;'&#41; == -1&#41; &#123;
                  			jndiName = &#40;new StringBuffer&#40;CONTAINER_PREFIX&#41;.append&#40;jndiName&#41;&#41;.toString&#40;&#41;;
                  		&#125;
                  		return jndiName;
                  	&#125;
                  &#125;
                  In your applicationContext.xml :

                  Code:
                  <bean id="propertyConfigurer" class="org.sprfr.EnvEntryPropertyPlaceholderConfigurer">
                      <property name="locations">
                  	  <list>
                  	    <value>classpath&#58;/app.properties</value>
                  	    <value>classpath&#58;/jdbc.properties</value>
                        </list>
                      </property>
                    </bean>
                  You add a context file descriptor in $CATALINA_HOME/conf/[enginename]/[hostname]/[context].xml where you define the environment entry :

                  Code:
                  <Context reloadable="false" debug="0">
                     	
                     	<Environment
                     		name="myentry"
                     		type="java.lang.String"
                     		value="myvalue"/>
                  
                  </Context>
                  And use it in your context:

                  Code:
                    <bean id="myBean" class="MyBean">
                      <property name="myProperty"><value>$&#123;myentry&#125;</value></property>
                    </bean>
                  You can also define a default value in your app.properties and set envEntryOverride to true on propertyConfigurer. So you could deploy your war without context descriptor. And if you need to override some properties, you create one.

                  Hope this helps.

                  Comment

                  Working...
                  X