6

In projects I work(ed) on, deployment parameters - such as storage path or DB login - are usually given through a parameter file, which is stored in the war file.

I find that unsuitable because those values needs to be changed each time the webapp is packaged for a different deployment (dev vs prod, change of executing computer). The source code being versioned, this makes it even more bothering.

Is there some better option to pass parameters such as listed above?

By better, I mean:

  • practical: simple to setup, change and explain to others
  • separated from the war
  • as independent as possible to the web container (if dependent, I'm using tomcat in prod)

Edit

I chose the answer of @aksappy to reward the work done in the answer and because it provided several methods using standard tools. However, depending on the context I could go for any other solutions:

Community
  • 1
  • 1
Juh_
  • 14,628
  • 8
  • 59
  • 92
  • I generate a jar containing these properties files separate from the war and add it as a dependency to the war. So, it won't matter the deployment environment, I deploy this jar with properties when necessary, then deploy and redeploy the war as much as I need. – Luiggi Mendoza May 26 '15 at 13:16
  • War files are supposed to contain all their dependencies. So what do you mean by "deploy this jar"? – Juh_ May 26 '15 at 13:19
  • 1
    Application servers usually provide a folder where these jars are available for all the applications deployed there e.g. for tomcat, the folder is `%CATALINA_HOME%/lib`, for JBoss (until version 6 if I remember well) is `%JBOSS_HOME%/server//lib`, and on. – Luiggi Mendoza May 26 '15 at 13:22
  • that is worth an answer :-) – Juh_ May 26 '15 at 13:26
  • "What is the correct approach?" is primarily opinion based, so this question may get closed. I'd suggest simply asking what the options are (hopefully that doesn't become too broad) and then evaluating for yourself which the best option is. – Anthony Grist May 26 '15 at 13:27
  • I was expecting that there would be one good/general approach... It looks to me that this is a design limitation :-/ But I'll edit my question. – Juh_ May 26 '15 at 13:34

4 Answers4

3

You can use a multitude of things based on your environment. Here are somethings which may be considered

  1. Use datasources The datasources defined in the server context removes the hard wired dependency of managing db configurations and connection pool from the web application. In Tomcat, this can be done as below in the context.xml
<Context>
       ...
      <Resource name="jdbc/EmployeeDB" auth="Container"
                 type="javax.sql.DataSource"
          description="Employees Database for HR Applications"/>
      </Context>
  1. Use Contexts

You can configure named values that will be made visible to the web application as environment entry resources, by nesting entries inside this element. For example, you can create an environment entry like this: (Source here). This can be set as context parameters or environment entries. They are equivalent to the entries made in a web.xml or a properties file except that they are available from the server's context.

  1. Use database configurations and load those configuration at ServletContextListener

Another approach which I tend to follow is to create a relational schema of properties in a database. Instead of loading the properties file during server startup, load the properties from the database during start up.

public class ContextInitialize implements ServletContextListener {
  private static Properties props;
  public void contextInitialized(ServletContextEvent servletContextEvent) {
     // connect to DB
     // Load all the key values pairs as required
     //put this into a Properties object, or create a hashtable, hashmap ..
  }
  //Getter
  public String getProperty(String key){
     // get value of key
  }
  //Setter
  public void setProperty(String key, String value){
     // set value to a key
  }
}

Note: above is just an example.

  1. Use environment variables or classpath variables

Use classpath / path variables in Environment variables and use System.getenv() in your java code to get these values as necessary.

aksappy
  • 3,400
  • 3
  • 23
  • 49
  • Thanks for the listing. Could you give a little more details on the pros&cons of each method, and maybe pointer on how to implement them? Note that I updated my question to remove the term "correct" and explain what qualities I am looking for (practicality and independence w.r.t. the servlet container) – Juh_ May 26 '15 at 14:43
1

We normally put our web app properties files in the Tomcat home folder. POJOS look on the launch folder. There will be other standard locations for other web servers.

  final String tomcatHome = System.getProperty("catalina.home");
  if (tomcatHome == null) {
    // POJOs look in "."
    searchPaths.add(".");
  } else {
    searchPaths.add(tomcatHome);
    webApp = true;
  }
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • I'm puzzled by the idea of having tomcat specialized code. However, this could be a method fitting my requirement if it covered several/most of the standard servlet container and deployment methods, for dev and prod. Can anyone create a lib for that :-) ? – Juh_ May 27 '15 at 07:52
1

An strategy is to pack all the properties and configuration files in an external jar and make this jar a dependency for your application(s): war, ear, etc. Then, you can deploy this jar in a common folder where the application server will load it and make it available for all the applications deployed there. This means that you will deploy the jar with the values for each environment once (or every time you need to change it, but its changes must be slow compared to the changes made to your main artifacts) and you can deploy and redeploy your war or any other project in your application server without problems.

In case of Tomcat, you may deploy this jar inside %CATALINA_HOME%/lib as explained in Tomcat Tutorial. Class Loader Definitions

To consume (read) these files in my application, I just load them like any other resource in my application.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • To be clear, you put the property file(s) in a jar (eg. `jar cf myapp-properties.jar myapp.properties`), add it in the servlet container classpath (such as the tomcat lib folder), then how do you read the files in the webapp? – Juh_ May 26 '15 at 14:21
  • 1
    Answer updated. Just read the file as another resource in your path. – Luiggi Mendoza May 26 '15 at 14:38
1

Two strategies I've used:

JVM Parameters -- Custom JVM parameters can be set by the container at startup. This can get a bit verbose though if you have a lot of settings.

Configuration Files -- These can be read by the application. Either the location is hardcoded, put inside the container path, or to get the best of both worlds, specify the location via a JVM parameter.

Necreaux
  • 9,451
  • 7
  • 26
  • 43
  • I am not managing the servlet container for prod, so that exclude the JVM parameter approach (it's still usable for dev though). I can also meet halfway with my current method and hardcode a path in the property of the war (eg `configDir=/etc/myapp`), and keep config outside of application. – Juh_ May 26 '15 at 15:14
  • You can also use the JVM parameter approach and have a default hard-coded value. That way if you can't set the JVM parameter you have a failback. It's a little unusual IMO to have access to the filesystem, but not JVM parameters. One other thing I forgot to mention is that some containers let you override servlet/web.xml values. – Necreaux May 26 '15 at 15:28
  • It is indeed unusual to access the filesystem. However, a a filesystem is a database (in its general sens) which is easy to deploy and has standard api :-) – Juh_ May 26 '15 at 15:37
  • The prod servlet container is used to run other webapp. wouldn't it be dangerous to change the JVM parameters? Also, is it possible to change those without restarting the container? – Juh_ May 26 '15 at 15:44
  • I actually want to avoid overriding the web.xml which is inside the war. Now, here I say "prod" quite lightly. I agree that in a proper industrial setup, it is not a problem to edit the war content before deployment. – Juh_ May 26 '15 at 15:46