I am having trouble with configuring a webapp in Tomcat 7. In my WAR file, there is a properties file myApp/WEB-INF/classes/myProps.props
, and it contains environment-specific properites. I am trying to override that configuration file on the server, so that the same WAR file will deploy to multiple environments.
I heard there was a way to do this using replacement config files in tomcat/conf/Catalina/myApp
. This is the method I am having trouble figuring out.
Also, myApp.war
is one of many running on the same Tomcat server, and it does not run as localhost. I want to be able to solve this problem for several of the webapps.
Server version: Apache Tomcat/7.0.23 Server built: Nov 20 2011 07:36:25 Server number: 7.0.23.0 OS Name: Linux
It doesn't "go in Tomcat". It goes in the web application (WAR). The best place to put a properties file would be in the webapp's WEB-INF/classes directory, which is part of the application classpath.
Provide the file name using context param or java system parameter. But, it is again property file location is war dependent. You should change war file to change propert file location. If i am correct the requirement was to change the props in the file , not the file as such.
Perhaps the simplest way to deploy a WAR file to Tomcat is to copy the file to Tomcat's webapps directory. Copy and paste WAR files into Tomcat's webapps directory to deploy them. Tomcat monitors this webapps directory for changes, and if it finds a new file there, it will attempt to deploy it.
Another thing we can do is to deploy it by simply dropping it into the $CATALINA_HOME\webapps directory of any Tomcat instance. If the instance is running, the deployment will start instantly as Tomcat unpacks the archive and configures its context path.
Your tomcat/conf/Catalina/<host>
can contain context descriptors that let you configure lots of things including defining "environment entries", which are accessible from Java via JNDI. There are lots of ways to go about using it. Personally, I set an environment entry which is the file system path to my properties file. My app is built to check for this entry, and if it doesn't exist, look for the file on the classpath instead. That way, in dev, we have the dev properties right there on the classpath, but when we build and deploy, we point it to an external file.
There's good documentation for configuring a context on the Tomcat website. See the Defining a Context section on details of how to create the file and where to put it.
As an example, if your host is named myHost
and your app is a war file named myApp.war
in the webapps
directory, then you could create tomcat/conf/Catalina/myHost/myApp.xml
with this content:
<Context> <Environment name="configurationPath" value="/home/tomcat/myApp.properties" type="java.lang.String"/> </Context>
Then from your code, you'd do a JNDI lookup on java:comp/env/configurationPath
(95% certainty here) to get that string value.
I like .properties
files instead of
javax.servlet.Filter
, javax.servlet.ServletContextListener
which my be inconvenientTomcat 7 Context hold Loader element. According to docs deployment descriptor (what in <Context>
tag) can be placed in:
$CATALINA_BASE/conf/server.xml
- bad - require server restarts in order to reread config$CATALINA_BASE/conf/context.xml
- bad - shared across all applications$CATALINA_BASE/work/$APP.war:/META-INF/context.xml
- bad - require repackaging in order to change config$CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml
- nice, but see last option!!$CATALINA_BASE/webapps/$APP/META-INF/context.xml
- nice, but see last option!!$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml
- best - completely out of application and automatically scanned for changes!!!Context
can hold custom Loader
org.apache.catalina.loader.VirtualWebappLoader (available in modern Tomcat 7, you can add own separate classpath to your .properties
), and Parameter
(accessed via FilterConfig.getServletContext().getInitParameter(name)
) and Environment
(accessed via new InitialContext().lookup("java:comp/env").lookup("name")
):
<Context docBase="${basedir}/src/main/webapp" reloadable="true"> <!-- http://tomcat.apache.org/tomcat-7.0-doc/config/context.html --> <Resources className="org.apache.naming.resources.VirtualDirContext" extraResourcePaths="/WEB-INF/classes=${basedir}/target/classes,/WEB-INF/lib=${basedir}/target/${project.build.finalName}/WEB-INF/lib"/> <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${basedir}/target/classes;${basedir}/target/${project.build.finalName}/WEB-INF/lib"/> <JarScanner scanAllDirectories="true"/> <Parameter name="min" value="dev"/> <Environment name="app.devel.ldap" value="USER" type="java.lang.String" override="true"/> <Environment name="app.devel.permitAll" value="true" type="java.lang.String" override="true"/> </Context>
If you use Spring and it's XML config:
<context:property-placeholder location="classpath:app.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.pass}"/> </bean>
With Spring injecting above properties into bean fields are easy:
@Value("${db.user}") String defaultSchema;
instead of JNDI:
@Inject ApplicationContext context; Enviroment env = context.getEnvironment(); String defaultSchema = env.getProperty("db.user");
Note also that EL allow this (default values and deep recursive substitution):
@Value('${db.user:testdb}') private String dbUserName; <property name='username' value='${db.user.${env}}'/>
See also:
NOTE With extending classpath to live directory you also allowed to externilize any other configs, like logging, auth, atc. I externilize logback.xml
in such way.
UPDATE Tomcat 8 change syntax for <Resources>
and <Loader>
elements, corresponding part now look like:
<Resources> <PostResources className="org.apache.catalina.webresources.DirResourceSet" webAppMount="/WEB-INF/classes" base="${basedir}/target/classes" /> <PostResources className="org.apache.catalina.webresources.DirResourceSet" webAppMount="/WEB-INF/lib" base="${basedir}/target/${project.build.finalName}/WEB-INF/lib" /> </Resources>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With