How to update external config files without rebuilding war file in Grails - grails

How to update external config files (e.g.: config-ex.groovy, config-ex.properties) without rebuilding the war file in Grails?
Restarting the application server will apply the new updates from external config files.

If I understand well you want to externalized Grails config outside the war.
You can define an external config in your config.groovy like this
grails.config.locations = ["file:path/to/your/Configfile.groovy"]
See the Grails doc 4.4 Externalized Configuration

Define your external Grails config with:
grails.config.locations = ["file:some/path/to/Config.groovy"]
Then to reload them at runtime, you can use code like this:
def config = grailsApplication.config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split('file:')[0]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}
I have the above code in an admin protected Controller.

Went around the houses for this one, thanks Gregg
For services or groovy src files you could use:
import org.springframework.context.ApplicationContext
ApplicationContext ctx = (ApplicationContext) org.codehaus.groovy.grails.web.context.ServletContextHolder.getServletContext().getAttribute(org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes.APPLICATION_CONTEXT);
def grailsApplication = ctx.getBean("grailsApplication")
ConfigObject config = ctx.getBean(GrailsApplication).config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split("file:")[1]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}
And for abstract classes that are typically extended from controllers:
import grails.util.Holders
def config = Holders.config
def locations = config.grails.config.locations
locations.each {
String configFileName = it.split("file:")[1]
config.merge(new ConfigSlurper().parse(new File(configFileName).text))
}

Related

eventConfigureTomcat Access to Config.groovy

Grails 2.5.0
I'm defining an alternate context root via _Events.groovy using the eventConfigureTomcat closure. To do this, I've got code like so..
eventConfigureTomcat = { tomcat ->
def newContextRoot = "/"
def newContextPath = new File("/full/path/to/context/root")
// more code below that doesn't matter for this question...
}
For the newContextPath I want to pull that value from my Config.groovy (which is actually pulling it from an external config file). I've tried using grails.util.Holders but it doesn't seem to be wired up at this specific event yet. Is this possible?
You can set the value from your Config.groovy as an environment variable and then use it in _Events.groovy. If you still need to pull from an external config file, run a bash script inside of .bashrc/.bashprofile (wherever you define the environment variable).
eventConfigureTomcat = { tomcat ->
String altctxroot = System.getenv("ALT_CTX_ROOT")
def newContextRoot = "/"
def newContextPath = new File("$altctxroot")
}

Why is Config.groovy variable not defined in plugin's config?

I have a Grails app (myapp) that uses a custom plugin (grails-fizz). In myapp's Config.groovy I have the following var defined:
logfile = "/opt/myapp/logs/myapp.log"
I then pull in grails-fizz as a plugin inside the app's BuildConfig.groovy file. In grails-fizz's FizzGrailsPlugin.groovy, I try to use that value:
def doWithApplicationContext = { ctx ->
println("The logfile is ${logfile}.")
}
When this runs I get the following error:
Error initializing the application: No such property: logfile for class: FizzGrailsPlugin
It seems that the plugin doesn't have scope/visibility over this var? What's the solution?
You can access configuration values through the configuration object.
def doWithApplicationContext = { ctx ->
def config = ctx.config
println println "The logfile is ${config.logfile}."
}
From the documentation
Every plugin has an implicit application variable which is an instance of the GrailsApplication interface.
So you can use application.config to access the configuration.

Access sub-project application properties in grails/groovy

I have a singleton class
#Singleton
class CustomerBundleSingleton {
def grailsApplication = Holders.getGrailsApplication()
String projName
private CustomerBundleSingleton() {
line 10: projName = // how to get sub-project name here ???
}
}
application.properties // my project is running
-----------------------
app.name = MyNewProject
application.properties // located in sub project
-----------------------
app.name = MySubProject
I tried grailsApplication.metadata['app.name'] in "line 10:" it returns "MyNewProject".Whereas I want a way to get the project name of the UserBundleSingleton located (MySubProjectName). Something like grailsApplication.current.metadata['app.name'] ???? .
So that it can give me back MySubProjectName instead of MyNewProject??
I have 3 suggestions depending on your requirements and your 'bundling'.
1) You don't have a bundle marker/descriptor
Assuming that you know the sub-project(Grails plugin) name, your life gets easier, instead of having to loop through all plugins...
You can probably use something among these lines.
// Plugin name is 'hibernate' in this example
import org.codehaus.groovy.grails.plugins.PluginManagerHolder
def hibernateVersion = PluginManagerHolder.pluginManager.getGrailsPlugin('hibernate').version
// Loop through all plugins
// PluginManagerHolder.pluginManager.getAllPlugins()
2) Using custom plugin properties to lookup plugins of interest
Other strategy, if you must lookup the bundle dynamically.
Create a custom marker property in each of your plugin descriptors
def specialProperty = "whatever"
Then inside your CustomerBundleSingleton
PluginManagerHolder.pluginManager.getAllPlugins().each {
if (it.properties.specialProperty) {
def subProjectName = it.name
def subProjectVersion = it.version
}
}
3) Custom bundle info resolution
You may also want to consider some metadata via META-INF/MANIFEST.MF or similar mechanism.
Hope it helps...

Grails access properties from environment file

In my Config.groovy I consolidate properties files in the following way:
grails.config.locations << "file:${userHome}/environment.properties" << "file:${userHome}/passwords.properties"
I have two problems:
When autowiring in the Service layer, with GrailsApplication I can retrieve properties defined in Config.groovy BUT NOT those properties defined in the files
I cannot autowire GrailsApplication in my Jobs (using Quartz plugin)
Can anyone shed light on these issues?
What I do is to have an external Config.groovy file, for instance: MyConfig.groovy
At the end of the standard grails Config.groovy file, I have the following:
def ENV_NAME = "MY_EXTERNAL_CONFIG"
if(!grails.config.locations || !(grails.config.locations instanceof List)) {
grails.config.locations = []
}
if(System.getenv(ENV_NAME)) {
grails.config.locations << "file:" + System.getenv(ENV_NAME)
} else if(System.getProperty(ENV_NAME)) {
grails.config.locations << "file:" + System.getProperty(ENV_NAME)
} else {
println "No external Configs found."
}
So now you can have a MyConfig.groovy file anywhere in production environment (for example) and then set an Environment system variable to point to this file (or pass it as parameter to startup.sh), before you start tomcat:
MY_EXTERNAL_CONFIG="/home/tomcat/configs/MyConfig.groovy"
export MY_EXTERNAL_CONFIG
That's it. Now you have an external MyConfig.groovy file. The properties in it are accessible from your grails app as they were part of the standard Config.groovy
import org.codehaus.groovy.grails.commons.*
//...
ConfigurationHolder.config.foo.bar.hello
how about trying this!(just a guess, it should not make any difference! however give it a shot and let me know if doesnt work!)
grails.config.locations = [ "file:${userHome}/environment.properties",
"file:${userHome}/passwords.properties" ]

Externalized grails.serverURL not accessible from Config.groovy

I have an application where the config is externalized. In Config.groovy, I'm updating
grails.config.locations=[file:/.../myapp-log4j.groovy, file:/.../myapp-config.properties]
That works fine for datasources and such. But later in Config.groovy, I have:
springws {
wsdl {
MyApp {
// In this case the wsdl will be available at <grails.serverURL>/services/v1/myapp/myapp-v1.wsdl
wsdlName= 'myapp-v1'
xsds= '/WEB-INF/myapp.xsd'
portTypeName = 'myappPort'
serviceName = 'myappService'
locationUri = "${grails.serverURL}/services/v1/myapp"
targetNamespace = 'http://www..../myapp/v1/definitions'
}
}
}
And ${grails.serverURL} contains [:] which is not what is in my config file. The config file contains (among the datasource details):
grails.serverURL=http://samiel:9011/xid
My guess would be that the updated grails.config.locations is only used after I return from Config.groovy.
So, what are my options to setup my web service details based on the externalized serverURL ?
This is what I get when I run your example (just confirming your starting postion):
def testExternalConfig() {
println "grails.serverURL: ${ConfigurationHolder.config.grails.serverURL}"
println "springws.wsdl.MyApp.locationUri ${ConfigurationHolder.config.springws.wsdl.MyApp.locationUri}"
}
--Output from testExternalConfig--
grails.serverURL: http://samiel:9011/xid
springws.wsdl.MyApp.locationUri http://localhost:8080/soGrails/services/v1/myapp
Like you said, Config.groovy does not see the value set in the external config. I believe that Grails processes external
configs after Config.groovy, and this test appears to confirm that. The logic being that you likely have external config file
values that you want to have precedence over config in war file.
Fix is to override the full property in myapp-config.properties:
grails.serverURL=http://samiel:9011/xid
springws.wsdl.MyApp.locationUri=http://samiel:9011/xid/services/v1/myapp
With that change I get this:
--Output from testExternalConfig--
grails.serverURL: http://samiel:9011/xid
springws.wsdl.MyApp.locationUri http://samiel:9011/xid/services/v1/myapp

Resources