6

Section 24.3 in Externalized Configuration indicates a .properties or .yml file can be used for external config, but I would like my external config to be a .groovy file just like my application.groovy file which I have already converted from .yml. How can I make this happen?

Grails version 3.2.0.M2

UPDATE:

I was able to get this working based on the answer provided by @Michal_Szulc

Note that the ConfigSlurper needed the current environment to work correctly. Also note that these changes are to be made to the my_grails_app/grails-app/init/my_grails_app/Application.groovy file, not the my_grails_app/grails-app/conf/application.groovy file which you may have if you converted from a .yml configuration to a .groovy configuration.

package my_grails_app

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.context.EnvironmentAware
import org.springframework.core.env.Environment
import org.springframework.core.env.MapPropertySource

class Application extends GrailsAutoConfiguration implements EnvironmentAware {
    static void main( String[] args ) {
        GrailsApp.run( Application, args )
    }

    @Override
    void setEnvironment( Environment environment ) {
        def appName = grails.util.Metadata.current.getApplicationName()

        // The value of this environment variable should be the absolute path to an external .groovy config file like /opt/my_grails_app/my_grails_app-config.groovy.
        def envVarName = "MY_GRAILS_APP_CONFIG"

        // If you don't want to use an environment variable you can specify your external .groovy config file here, but the environment variable will still be checked first.
        def dfltAppConfigFileName = "/opt/${ appName }/${ appName }-config.groovy"
        def appConfigFile = null
        def loadDfltConfig = false

        // Try to load config specified by the environment variable first
        println "Checking the environment variable ${ envVarName } for the configuration file location..."
        def envVarVal = System.getenv( envVarName ) ?: System.getProperty( envVarName )
        if( envVarVal ) {
            appConfigFile = new File( envVarVal )
            if( !appConfigFile.exists() ) {
                println "The configuration file ${ appConfigFile } specified by the environment variable ${ envVarName } does not exist.  Checking for the default configuration file ${ dfltAppConfigFileName } instead..."
                appConfigFile = null
                loadDfltConfig = true
            }
        } else {
            println "The environment variable ${ envVarName } which specifies the configuration file to be loaded does not exist.  Checking for the default configuration file ${ dfltAppConfigFileName } instead..."
            appConfigFile = null
            loadDfltConfig = true
        }

        // Try loading the default config file since we couldn't find one specified by the environment variable
        if( loadDfltConfig ) {
            appConfigFile = new File( dfltAppConfigFileName )
            if( !appConfigFile.exists() ) {
                println "The default configuration file ${ dfltAppConfigFileName } does not exist."
                appConfigFile = null
            }
        }

        // Load the config file if it exists, otherwise exit
        if( appConfigFile ) {
            println "Loading configuration file ${ appConfigFile }"
            def config = new ConfigSlurper( environment.activeProfiles.first() ).parse( appConfigFile.toURI().toURL() )
            environment.propertySources.addFirst( new MapPropertySource( "${ appName }-config", config ) )
        } else {
            println "No configuration file found.  Exiting."
            System.exit( 1 )
        }
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179

3 Answers3

3

I found this thread and quotation by Graeme Rocher:

Grails 3 uses Spring's property sources concept, so it will resolve properties from the system, the environment and finally the application.yml/application.groovy

and code by Clyde Balneaves:

class Application extends GrailsAutoConfiguration implements EnvironmentAware {
    static void main(String[] args) {
    GrailsApp.run(Application)
    }

    @Override
    void setEnvironment(Environment environment) {
    //Set up Configuration directory
    def krakenHome = System.getenv('KRAKEN_HOME') ?: System.getProperty('KRAKEN_HOME') ?: "/opt/kraken"

    println ""
    println "Loading configuration from ${krakenHome}"
    def appConfigured = new File(krakenHome, 'KrakenConfig.groovy').exists()
    println "Loading configuration file ${new File(krakenHome, 'KrakenConfig.groovy')}"
    println "Config file found : " + appConfigured

    if (appConfigured) {
        def config = new ConfigSlurper().parse(new File(krakenHome, 'KrakenConfig.groovy').toURL())
        environment.propertySources.addFirst(new MapPropertySource("KrakenConfig", config))
    }
    }
}
Michal_Szulc
  • 4,097
  • 6
  • 32
  • 59
  • 1
    Thanks, this got me on the right path. I had to make some changes which I noted in an update to my question. – ubiquibacon Jul 29 '16 at 01:06
  • 1
    Thank You Michal_Szulc : This helps me to read a external Application.groovy file but external file configuration are not applicable if same configurations are present in application.yml file. Can you please help me on this. – Shashank.gupta40 Jan 11 '17 at 12:22
  • I think it's made on purpose - imho application.yml should be favored over others config files. – Michal_Szulc Jan 12 '17 at 15:35
0

May be you can also try this way (Overriding run method)

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import grails.util.Environment
import grails.util.Holders
import org.springframework.boot.CommandLineRunner

class Application extends GrailsAutoConfiguration implements CommandLineRunner {

    static void main(String[] args) {
        GrailsApp.run(Application, args)
    }

    @Override
    void run(final String... args) throws Exception {
        println "Running in ${Environment.current.name}"

        // Get configuration from Holders.
        def config = Holders.getConfig()
        def locations = config.grails.config.locations
        locations.each {
            String configFileName = it.split("file:")[1]
            File configFile = new File(configFileName)
            if (configFile.exists()) {
                config.merge(new ConfigSlurper(Environment.current.name).parse(configFile.text))
            }
        }
    }
}
Adi
  • 11
  • 1
  • 1
    When giving an answer it is preferable to give some explanation as to WHY your answer is the one. – Stephen Rauch Jan 22 '17 at 06:02
  • I did. I said may be you can also try in another way also. It's just another solution that I found – Adi Jan 23 '17 at 06:53
  • 1
    Your answer did not explain why you thought it was THE answer. It simply suggested that it might be worth a try. Try to keep in mind that the point of Stack Overflow is to put answers up that will allow other people to make use of them in the future. If you don't explain why your answer works, it will not be very useful for the next person that comes along. – Stephen Rauch Jan 23 '17 at 06:57
  • I said you can also try THIS way. and the solution that I have given worked for me in my pc and that's the reason I pasted this solution here. I think stack overflow has some thing like upvote and downvote for the same (To tell whether the solution works or not). – Adi Jan 24 '17 at 08:09
0

I think what you're looking for (and is much much easier/cleaner to boot) is the Grails External Config plugin.

James
  • 1,391
  • 2
  • 14
  • 20