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.
Related
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")
}
I created a Grails plugin (grails create-plugin myplugin1) and noticed that there was no myapp1/grails-app/conf/BootStrap.groovy created like you normally get when you create a Grails app.
I created one like so:
class BootStrap {
def init = {
println("Hello! The plugin is bootstrapping...")
}
def destroy = {
}
}
I then include the plugin with a Grails app (by adding myplugin1 as a plugin inside the app's BuildConfig.groovy). When I issue a grails run-app, I don't see the above println ever executing.
Do Grails plugins not use BootStrap.groovy? If so, where should I put "bootstrap" code that needs to be executed when a plugin is loaded? Otherwise, if I was correct to do this above, why might I not be seeing the "Hello! The plugin is bootstrapping..." message print out?
As always, start with the very well written and maintained documentation.
Plugins do not include Bootstrap.groovy. The following are excluded from plugins (taken from documentation).
grails-app/conf/BootStrap.groovy
grails-app/conf/BuildConfig.groovy (although it is used to generate dependencies.groovy)
grails-app/conf/Config.groovy
grails-app/conf/DataSource.groovy (and any other *DataSource.groovy)
grails-app/conf/UrlMappings.groovy
grails-app/conf/spring/resources.groovy
Everything within /web-app/WEB-INF
Everything within /web-app/plugins/**
Everything within /test/**
SCM management files within /.svn/ and /CVS/
In order to run code on startup of your plugin you need to hook into the runtime configuration of your plugin by using the doWithSpring or doWithApplicationContext (depending on what you need to do).
All of this, and more, is explained in the documentation. An example might be:
// MyFancyPlugin.groovy
...
def doWithApplicationContext = { appCtx ->
def sessionFactory = appCtx.sessionFactory
// do something here with session factory
}
...
Plugin's BootStrap is EXCLUDED from the plugin package. You have to do your init-phase in the plugin descriptor, in one or several of the following closures:
def doWithSpring = {
def appName = application.metadata.'app.name'
}
def doWithDynamicMethods = { ctx ->
// TODO Implement registering dynamic methods to classes (optional)
}
def doWithApplicationContext = { applicationContext ->
// TODO Implement post initialization spring config (optional)
}
Code that needs to run at startup time should go in the doWithApplicationContext closure in the plugin descriptor (MyPlugin1GrailsPlugin.groovy).
Alternatively, call it something else (e.g. MyPluginBootStrap.groovy), as it's only the specific classes BootStrap and UrlMappings that are excluded when a plugin is packaged, but any class whose name ends BootStrap is considered a bootstrap artefact.
I am trying to load the properties file externally, by setting up the system environment.
In my config.groovy file,
println "Config file location --->" + System.getenv("SAM_ENV")
grails.config.locations = ["file:"+ System.getenv("SAM_ENV")]
I have set the system env SAM_ENV value as C:\test\config.properties.
When I try to run the application,I am getting the print value as
Config file location ---> C:\test\config.properties prints properly.
The problem is when I try to access the properties file in my controller as
print "PAGINATION1"+grailsApplication.config.PAGINATION1
the value of PAGINATION1 is not getting printed properly.
Can any one help me what configuration has to be done to access the external properties file in grails application.
Add the below line in config.groovy
grails.config.locations = [ "classpath:grails-app-config.properties"]
environments {
development {
grails.logging.jul.usebridge = true
grails.config.locations = ["file:C:\\conf\\externalfile.groovy"]
}
production {
grails.logging.jul.usebridge = false
grails.config.locations = ["file:/opt/config/externalfile.groovy"]
// TODO: grails.serverURL = "http://www.changeme.com"
}
}
If you want to access any property from external configuration(config.groovy) then just declare the property like
property = property value eg:(ImagePath = "C:\\Users\\Saved Pictures")
access it like grailsApplication.config."property"
eg:(grailsApplication.config.ImagePath)
NOTE: dont use def just a property and its value.
What you're looking for is extending the classpath, which you can achieve by adding a post compilation event in _Events.groovy. Try this:
eventCompileEnd = {
ant.copy(todir:classesDirPath) {
fileset(file:"C:\test\config.properties")
}}
You can find more help here
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))
}
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