Monday, August 1, 2011

Grails Plugins and Default Configs

I've been working on Grails plugins for jQueryUI and YUI2.  One of my ideas was to use a default config within my plugin, which the plugin consumer could override and modify the config values for their usage.

Unfortunately, Grails doesn't provide this feature by default.  You can use the plugin's Config.groovy for settings when you test, but it doesnt work when the plugin is being ran from an app.  Unless...  you do the following.

Lets say your creating the next awesome plugin.  We'll call it Foo.

1.  Create a groovy config file that is unique to your plugin.  Mine is FooConfig.groovy. Inside, put your config values.
fooConfig {
  fooVar = "Hello World"
}

2.  Load your new config via the FooGrailsPlugin.groovy file.  This code is a modified version of the code found in Spring-Security-Core plugin.  Thanks Burt.
def doWithSpring = {
  mergeConfig(application)
}
private void mergeConfig(GrailsApplication app) {
  ConfigObject currentConfig = app.config.grails.fooConfig
  ConfigSlurper slurper = new ConfigSlurper(Environment.getCurrent().getName());
  ConfigObject secondaryConfig = slurper.parse(app.classLoader.loadClass("FooConfig"))

  ConfigObject config = new ConfigObject();
  config.putAll(secondaryConfig.fooConfig.merge(currentConfig))

  app.config.grails.fooConfig = config;
}

3.  Finally, we need to make our plugin config reload when a config is changed elsewhere in the application.
def onConfigChange = { event ->
  this.mergeConfig(application)
}

Thats it. Thats all I had to do. Now I can use default configs within my plugin and allow my plugin consumers to customize. Fun Stuff.

Here is an example of customization...
grails.fooConfig.fooVar = "I've been updated!"

Full Disclosure : I havent tested this in a deployed WAR yet.
Works from run-war.

Referenced Links
Post 1
Post 2

6 comments:

Peter Ledbrook said...

You might be interested in Daniel's Plugin Config Plugin for solving this problem.

Stephen Westfall said...

Thanks Peter. I'll check it out.

Daniel Henrique Alves Lima said...

Hi Stephen.

I agree with Peter ;-) After writing some plugins, if this task of merging to become tedious, try plugin-config.
We discussed it here: dev mailing list

More examples:

I'm using a verified map, but you can use a ConfigObject instead (application.mergedConfig.grails.plugin.freemarker)

FreemarkerGrailsPlugin.groovy
FreemarkerDefaultConfig.groovy


And

Plugin config test-plugins

Best regards,

Daniel.

Jean-Alain Geay said...

Thanks Stephen for the tip. I don't manage to override the plugin's default config in the consumer application's Config.groovy, though. The Config.groovy script is executed before the doWithSpring closure of the plugin. Any idea ? I'm using Grails v2.2.0.

Stephen Westfall said...

Jean-Alain Geay :

Sorry, I dont have much experience with Grails 2.x - this was written against Grails 1.3.x and I've since left the Grails ecosystem.

Best of luck finding a solution.

Jean-Alain Geay said...

Please ignore my previous comment. The execution of the app's Config.groovy before the doWithSpring closure of the plugin is not a problem. It still works properly in Grails 2.2!