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 theapp.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()
toFooGrailsPlugin.doWithApplicationContext
and/orFooGrailsPlugin.doWithDynamicMethods
anddestroy()
to FooGrailsPlugin.onShutdown, and deleteBootStrap.groovy
- add a dependency for the
release
plugin inBuildConfig.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
toFooGrailsPlugin.doWithSpring
and deleteresources.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 particularerror.gsp
,index.gsp
, andlayouts/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
, andApplicationResources.groovy
intograils-app/conf
, merging if needed - Move
resources.groovy
intograils-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
- Move code from
FooGrailsPlugin.doWithApplicationContext
andFooGrailsPlugin.doWithDynamicMethods
toBootStrap.groovy
init()
, and code fromFooGrailsPlugin.onShutdown
todestroy()
- Move bean definitions from
FooGrailsPlugin.doWithSpring
toresources.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 fromBuildConfig.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
, rungrails install-templates
and add them tosrc/templates/war/web.xml
- If you add custom artifacts, or were supporting development-environment code or config changes in
onChange
and/oronConfigChange
, these aren’t directly doable in an application. Use the pluginator plugin for these, and also for dynamicweb.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.