Configuration depending on launch mode
Asked Answered
K

3

12

Play can be launched in dev mode (via run), in production mode (via start) or in test mode. Is there a way to provide a different config file (conf/application.conf) depending on which mode it is launched in?

Kareem answered 11/6, 2015 at 17:50 Comment(2)
What Playframework version do you use?Suggestible
@MonCalamari 2.4 atm, will upgrade to 3.0 sometime.Kareem
S
17

I usually have a base configuration (application.conf) and three extra configs per environment. In Play Framework 2.4 it can be done by extending GuiceApplicationLoader and merging base conf with your environment specific conf. You can go one step forward and provide different guice modules per environment.

Scala version:

class CustomApplicationLoader extends GuiceApplicationLoader {

    override protected def builder(context: Context): GuiceApplicationBuilder = {
        val builder = initialBuilder.in(context.environment).overrides(overrides(context): _*)
        context.environment.mode match {
            case Prod =>
                // start mode
                val prodConf = Configuration(ConfigFactory.load("prod.conf"))
                builder.loadConfig(prodConf ++ context.initialConfiguration).bindings(new ProdModule());
            case Dev =>
                // run mode
                val devConf = Configuration(ConfigFactory.load("dev.conf"))
                builder.loadConfig(devConf ++ context.initialConfiguration).bindings(new DevModule());
            case Test =>
                // test mode
                val testConf = Configuration(ConfigFactory.load("test.conf"))
                builder.loadConfig(testConf ++ context.initialConfiguration).bindings(new TestModule());
        }
    }
}

Java version:

public class CustomApplicationLoader extends GuiceApplicationLoader {

    @Override
    public GuiceApplicationBuilder builder(ApplicationLoader.Context context) {
        final Environment environment = context.environment();
        GuiceApplicationBuilder builder = initialBuilder.in(environment);
        Configuration config = context.initialConfiguration();
        if (environment.isTest()) {
            config = merge("test.conf", config);
            builder = builder.bindings(new TestModule());
        } else if (environment.isDev()) {
            config = merge("dev.conf", config);
            builder = builder.bindings(new DevModule());
        } else if (environment.isProd()) {
            config = merge("prod.conf", config);
            builder = builder.bindings(new DevModule());
        } else {
            throw new IllegalStateException("No such mode.");
        }
        return builder.in(environment).loadConfig(config);
    }

    private Configuration merge(String configName, Configuration currentConfig) {
        return new Configuration(currentConfig.getWrappedConfiguration().$plus$plus(new play.api.Configuration(ConfigFactory.load(configName))));
    }
}

Do not forget to include play.application.loader = "modules.CustomApplicationLoader" to your application.conf.

In lower versions of Play something similar can be achieved by using GlobalSettings class and overriding onLoadConfig. Mind GlobalSettings in Play 2.4 is depracted.

If you don't like including test.conf and test mocks from TestModule to your production build, you can filter the files with sbt.

Suggestible answered 12/6, 2015 at 7:8 Comment(6)
And add play.application.loader = "modules.CustomApplicationLoader" into application.conf?Kareem
Yup. Follow the link in the answer for more details.Suggestible
I think the stackoverflow policy is to copy/paste things over because links can go dead.Kareem
Yeah true, however an answer doesnt looks neat with a link pasted. :-)Suggestible
When I follow the approach above in Scala, I get a ConfigurationException: Guice configuration errors: 1) No implementation for play.api.Application was bound.. Am I missing something?Bueschel
Doesn't work in test mode for me. groups.google.com/forum/#!topic/play-framework/JnxK4MiQf74Threnody
D
3

You can set a different config file using one of the 3 ways play gives to you:

1 - Using -Dconfig.resource

It will search for an alternative configuration file in the application classpath (you usually provide these alternative configuration files into your application conf/ directory before packaging). Play will look into conf/ so you don’t have to add conf/.

$ /path/to/bin/ -Dconfig.resource=prod.conf

2 - Using -Dconfig.file

You can also specify another local configuration file not packaged into the application artifacts:

$ /path/to/bin/ -Dconfig.file=/opt/conf/prod.conf

3 - Using -Dconfig.url

You can also specify a configuration file to be loaded from any URL:

$ /path/to/bin/ -Dconfig.url=http://conf.mycompany.com/conf/prod.conf

Checkout more on:

https://www.playframework.com/documentation/2.3.x/ProductionConfiguration

Dolhenty answered 11/6, 2015 at 21:12 Comment(1)
Yes, I know how to specify configs, but I'm specifically looking for how to specify configuration options depending on run/start/test, e.g. javaOptions in RunKareem
B
1

This thing can be done by having loading config files based on the environment which can be supplied via -Dmode=staging/dev/prod, and for loading the files I override onLoadConfig of GlobalSettings in Global.java.

Java snippet-

 @Override
 public Configuration onLoadConfig(Configuration config, File file,ClassLoader classLoader) {
 Configuration updatedConfig = config;
 String mode = config.getString("mode");
 if (StringUtils.isNotEmpty(mode)) {
   try {
     File modeFolder = FileUtils.getFile(file, "conf/" + mode);
     if (modeFolder.exists()) {
       play.api.Configuration modeConfig = config.getWrappedConfiguration();
       IOFileFilter fileFilter = new WildcardFileFilter("*.conf");
       Collection<File> fileList = FileUtils.listFiles(modeFolder, fileFilter, null);
       for (File confFile : fileList) {
         modeConfig = modeConfig
            .$plus$plus(new play.api.Configuration(ConfigFactory.parseFile(confFile)));

      }
       updatedConfig = new Configuration(modeConfig);
     }
   } catch (Exception e) {
     Logger.error("Exception while loading configuration for mode : " + mode, e);
   }
 } else {
   Logger.error("Please provide mode in which play application has to start (Ex. play -Dmode=<mode>) ");
 }

For each mode, create a folder(name same as environment) and keep environment specific config in that folder.

Buzzer answered 18/11, 2015 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.