1

This relates to this answer: System.getProperty("catalina.base") There can be scenario where client may use any other server

another server-independent system property yourself, you can set as a VM argument.

-Dconfig.location=/path/to/folder

In case of Tomcat, you can set it as JAVA_OPTS environment variable, or edit the catalina.bat startup file or edit the Windows Service settings (when it's installed as Windows Service), etc. Other servers supports similar constructs as well.

Is this considered 'clean'? We've been doing this for years, just want to know if this is acceptable, or there is a better way to configure runtime environment.

Community
  • 1
  • 1
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
  • To the answerers: please note that the linked question states that the property must be modifiable without rebuilding the WAR. Otherwise an `` is indeed a very obvious choice. – BalusC May 25 '11 at 11:06
  • @BalusC. So, is this an OK option? Only asking because it has always seemed like a hack to me. But sometimes if it works, it works. – Alexander Pogrebnyak May 25 '11 at 11:25
  • It feels maybe dirty, but there are apart from putting it in the classpath really no better ways if the requirement is to untouch the WAR whenever you want to change the location of external configuration files (not as far as I know, I would otherwise have answered it instead :) ). – BalusC May 25 '11 at 11:27
  • @BalusC. Can you, then, put your last comment as an answer, so I can accept it? – Alexander Pogrebnyak May 25 '11 at 11:41

5 Answers5

1

My understanding is that "more clean" would be using either <servlet-param> <init-param> in web.xml or some kind of IoC solution, like Spring.

Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
  • 1
    web.xml customization is fine for static tuning of the application. However, because it's produced at compile time, and in many cases is buried in .war bowels, it's not ideal for the last-minute runtime configuration changes. – Alexander Pogrebnyak May 24 '11 at 19:47
  • @Alexander, you use both, you can rely on a system prop (they can also be altered dynamically) and on init-param. init-param takes precedence (and the system-prop is used if lacking) – bestsss May 25 '11 at 07:47
  • I would have used `` instead, but that does not really **answer** the question. The requirement is to be able to untouch the WAR. – BalusC May 25 '11 at 11:06
1

I feel this is not the cleanest of ways to attain what you want. You can use the web.xml init params or servlet params tags.
Another way is using properties file or an XML configuration file.

Sid
  • 4,893
  • 14
  • 55
  • 110
  • This requires a rebuild of the webapp whenever you want to change the location. This is undesired in case of the original question. – BalusC May 25 '11 at 11:03
  • The whole point of having properties file is not to rebuild the application. It just needs a server reboot. On the other hand, if you want to do away with server reboot, you can maintain values in a database. – Sid May 25 '11 at 16:14
1

It feels maybe dirty, but there are apart from putting it in the classpath really no better ways if the requirement is to untouch the WAR whenever you want to change the location of external configuration files.

If untouching the WAR is not a strict requirement and rebuilding the WAR is allowed (e.g. you're using an inhouse developed application with continuous integration and serveradmins are in the same line, etc), then you could also use a <context-param> in web.xml instead.

<context-param>
    <param-name>config.location<param-name>
    <param-value>/path/to/file</param-value>
</context-param>

It's then in any Servlet (or better, ServletContextListener) available by ServletContext#getInitParameter():

String configLocation = servletContext.getInitParameter("config.location");
File configFile = new File(configLocation, "config.properties");
// ...
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
1

I just solved a similar problem in a slightly different way. Our customer wants to configure database connection details, integration server locations and ports etc. without rebuilding the war. Using environment property to point an external file containing the information may or may not be okay, but it felt a bit dirty trick. Anyway, here's a slightly more enterprisey way.

For database connections we use JNDI lookup and below is the current solution for integration server parametrization. The parameters can come from at least three different sources now:

  1. properties-file, which is overridable with Maven profiles and requires single line of xml in spring configuration to be accessible. This is obviously inside the war file.
  2. web.xml context-param. This is also, of course, inside the war file.
  3. Tomcat server can override the init parameters with context.xml which can be outside the war. This happens to be the same file where JNDI context is defined, which is nice.

Below is the implementation for configuration accessor bean. It can run in servlet context and also without one (for some unit tests it makes little sense to kickstart a full-blown web server, but we nevertheless need to satisfy spring bean injections).

I don't mean this to be a perfect solution, but it is one. Didn't find anything like this with google.

@Service
public class IntegrationConfigurationImpl implements
   IntegrationConfiguration, InitializingBean,
   ServletContextAware, ApplicationContextAware  {

private static final String SERVER_HOST_PROPERTY = "integration.server.host";
private static final String SERVER_PORT_PROPERTY = "integration.server.port";
private static final String PROPERTY_BEAN_NAME = "integrationProperties";

private ServletContext servletContext;
private ApplicationContext applicationContext;

private static final Logger log = LoggerFactory.getLogger(IntegrationConfigurationImpl.class);
private String serverHost = "foo";
private int serverPort  = 42;

@Override
public String getServerHost() {
    return serverHost;
}

@Override
public int getServerPort() {
    return serverPort;
}

@Override
public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
}

@Override
public void afterPropertiesSet() throws Exception {
    // konfiguraation validointi..
    if (servletContext == null) {
        log.info("servlet context not set, not running as a web application. Trying to get properties from application context");
        if (applicationContext.containsBean(PROPERTY_BEAN_NAME)) {
            Properties p = (Properties)applicationContext.getBean(PROPERTY_BEAN_NAME);
            serverHost = p.getProperty(SERVER_HOST_PROPERTY);
            serverPort = Integer.valueOf(p.getProperty(SERVER_PORT_PROPERTY)).intValue();
        } else {
            log.info("Property bean not found :" + PROPERTY_BEAN_NAME);
        }
    } else {
        serverHost = servletContext.getInitParameter(SERVER_HOST_PROPERTY);
        serverPort = Integer.valueOf(servletContext.getInitParameter(SERVER_PORT_PROPERTY)).intValue();
    }
    log.info("Using integration server " + getServerHost() + ", port " + getServerPort());
}

}

lokori
  • 436
  • 5
  • 6
0

The disadvantage with having system property is you need to restart the container to modify the system parameter.

Having it as init-param in web.xml, can allow you to modify by just restarting the web app.

Having in init-param is a better way.

Ramesh PVK
  • 15,200
  • 2
  • 46
  • 50
  • This requires a rebuild of the webapp whenever you want to change the location. This is undesired in case of the original question. – BalusC May 25 '11 at 11:04