Converting Grails Applications to Plugins and vice versa

I was in London last week on vacation with my family and was lucky that there was a London GGUG meetup during my visit. David Dawson discussed modularizing Grails applications by refactoring them into multiple plugins (you can see the video of his talk here). One thing that he mentioned was the idea of plugins that can be run like standalone applications since the structures of Grails applications and plugins are so similar, and I thought it would be interesting to look at the process of converting an application to a plugin or a plugin to an application.

The approaches I’ll discuss here include a lot of bias on my part about how I like to create apps and plugins, so YMMV. I also won’t go into partial conversions since David covered this well in his talk.

So to convert an application to a plugin, the general workflow would be something like

  • Create the plugin descriptor, FooGrailsPlugin.groovy. The easiest way to do this is to run grails create-plugin pluginname and copy the generated file from there
  • delete everything from application.properties except the app.grails.version property
  • if you have jars in the lib directory that are available in a Maven repo, delete them and replace with BuildConfig.groovy dependencies
  • change any plugin and jar dependencies that are needed for development and testing but not when the plugin is installed to not be exported, by adding export = false
  • If you need the _Install.groovy, _Uninstall.groovy, or _Upgrade.groovy scripts (you probably don’t) grab those from the dummy plugin from step 1 (but delete any you don’t need, they’re all optional)
  • delete ApplicationResources.groovy if you aren’t using it and don’t depend on resources plugin
  • move code from BootStrap.groovy init() to FooGrailsPlugin.doWithApplicationContext and/or FooGrailsPlugin.doWithDynamicMethods and destroy() to FooGrailsPlugin.onShutdown, and delete BootStrap.groovy
  • add a dependency for the release plugin in BuildConfig.groovy
  • delete everything but the log4j configuration from Config.groovy
  • delete UrlMappings.groovy unless you have exported mappings; only keep the added ones
  • move bean definitions from resources.groovy to FooGrailsPlugin.doWithSpring and delete resources.groovy
  • delete grails-app/i18n message bundle files unless you added messages; only keep the added ones
  • delete everything from grails-app/views that you don't use (in particular error.gsp, index.gsp, and layouts/main.gsp)
  • delete everything from web-app that you don't use (including WEB-INF xml and tld files)
  • now would be a great time to write those tests you've been meaning to get to
  • create one or more test applications to install the plugin into to ensure that it works as a plugin; consider scripting this
  • write documentation for how to use the plugin; at a minimum a README file, but Grails gdoc files would be much better (run grails doc --init to get started)

Converting a plugin to an application is similar, except for the most part reversed:

  • Create a dummy application with grails create-app appname to copy missing files from
    • Move BootStrap.groovy, Config.groovy, UrlMappings.groovy, and ApplicationResources.groovy into grails-app/conf, merging if needed
    • Move resources.groovy into grails-app/conf/spring
    • Move message bundle files to grails-app/i18n, merging if needed
    • Move missing GSPs to grails-app/views
    • Move static resources from web-app
    • Move xml and tld files from web-app/WEB-INF
  • Move code from FooGrailsPlugin.doWithApplicationContext and FooGrailsPlugin.doWithDynamicMethods to BootStrap.groovy init(), and code from FooGrailsPlugin.onShutdown to destroy()
  • Move bean definitions from FooGrailsPlugin.doWithSpring to resources.groovy
  • Delete the plugin descriptor
  • Restore missing properties in application.properties
  • Delete the _Install.groovy, _Uninstall.groovy, and _Upgrade.groovy scripts
  • Remove the dependency for the release plugin from BuildConfig.groovy
  • Now would be a great time to write those tests you've been meaning to get to
  • If you make changes in the plugin's doWithWebDescriptor, run grails install-templates and add them to src/templates/war/web.xml
  • If you add custom artifacts, or were supporting development-environment code or config changes in onChange and/or onConfigChange, these aren't directly doable in an application. Use the pluginator plugin for these, and also for dynamic web.xml changes that require runtime logic

  • I've probably skipped a few steps and definitely omitted a lot of detail, but this should cover most of the process for each type of conversion.

6 Responses to “Converting Grails Applications to Plugins and vice versa”

  1. jljouannic says:

    Am I wrong if I say the BootStrap class can also be renamed to something like FooGrailsBootStrap instead of moving its content to the FooGrailsPlugin.groovy file as you suggest?

    • sola says:

      I am also interested in this because this is a much more elegant/intuitive solution than transforming BootStrap.groovy.

      Burt: any comment on this? Does Grails 2.3.x still support using FooGrailsBootStrap.groovy style bootrstrapping in the plugins?

  2. Phillip says:

    Looks like application.properties also (still?) requires app.name.

    Deleting that property leads to a rather opaque message:
    java.lang.IllegalArgumentException: Property source name must contain at least one character

    Which, when further explored, is found when constructing an instance of org.springframework.core.env.PropertySource via org.codehaus.groovy.grails.commons.env.GrailsEnvironment.GrailsConfigPropertySource.

  3. It looks like plugin conversation may be easier.
    For example, why do we need to move beans from resources.groovy
    to FooGrailsPlugin.doWithSpring?
    We can load beans form resources.groovy as usual.
    Same for other files.

    • Burt says:

      resources.groovy isn’t included in the zip by default – it’s typically only used for local development/testing. You get get it included, but it’s nonstandard since there’s a well-defined place in the descriptor for configuring Spring beans.

Leave a Reply

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.