It’s Alive! CFML Plugin for Grails

Nothing to distribute quite yet, but I’m psyched that I just successfully hit an index.cfm in my nascent CFML plugin for Grails. What this means is that (when it’s done anyway) you’ll be able to run CFML from within a Grails application.

Why is this cool? Partially just because it’s fun to mess around with, but there are several practical reasons as well. Here’s a few off the top of my head:

  • Leverage the power of Grails for building the model and controller layer of an application while using CFML for the view
  • Integrate existing CFML functionality or entire CFML applications within the context of a Grails application
  • Write hybrid Grails and CFML applications, mixing and matching CFML and Groovy/Grails code in various sections of the application
  • Use Grails URL mappings to hit CFML or Groovy code based on URL patterns

Creating the plugin was actually relatively simple. The Grails plugin architecture is amazingly powerful and easy to use, and after Graeme Rocher’s two sessions on plugin development today at SpringOne2GX I at least had an idea of how this would be accomplished. I created a new Grails plugin project, dropped the Open BlueDragon JAR files into the Grails plugin’s lib directory, defined the servlets, servlet mappings, and a few other things in the Grails plugin config file, and a basic index.cfm file was processed fine.

I’m still thinking through all the possibilities and potential problems I might run into with this but at least it’s limping along. Exciting stuff, and shows the extreme power of the Grails plugin architecture.

Session Notes – Grails Plugin System Part 2

Presenter: Graeme Rocher

Technical Plugins

  • typically a bit more complicated to implement
  • can mix and match technical and functional plugins
  • provide programming apis

Key Concepts

  • plugin lifecycle
  • GrailsApplication object
    • encapsulates the conventions in a project
  • Spring BeanBuilder
    • runtime spring configuration–need to understand the spring dsl
  • Metaprogramming

Plugin Lifecycle Hooks

  • enclosures that allow you to manipulate the grails runtime
  • def doWithWebDescriptor = { xml -> }
    • useful for creating plugin that manipulates web.xml
  • def doWithSpring = {}
    • can use full power of spring within a grails plugin
    • written in groovy so have full access to groovy in configuring spring
  • def doWithDynamicMethods = { applicationContext -> }
    • metaprogramming
    • e.g. could add a method that interacts with hibernate
    • since you have access to the applicationContext you have access to more or less everything
  • def doWithApplicationContext = { applicationContext -> }
    • post-processing

doWithWebDescriptor

  • programmatic modification of generated web.xml
  • useful for integrating third-party servlets/filters
  • groovy markupbuilder style dsl
    • easy to append to existing nodes in xml
  • automates a lot of configuration you’d otherwise have to do by hand
  • doesn’t happen during war deployment

doWithSpring

  • programmatically modify Spring ApplicationContext
  • groovy dsl that generates spring xml

doWithDynamicMethods

  • exercise your groovy metaprogramming skills
  • add new methods and properties to existing types
  • “delegate” is equivalent to “it” in metaprogramming
  • in java terms a lot of what you have to do is DI, etc. and your code becomes rather cluttered
    • e.g. in GORM there’s no reference to the fact that you’re using Hibernate in your domain classes
    • specific references are abstracted away

Additional Hooks

  • onChange
    • can re-add a method to a class when it changes
    • e.g. specify def observe = [‘plugins’] to watch for changes
  • onConfigChange

Plugin Life-Cycle Illustrated

  • grails loads first
  • loadPlugins() called next — pluginmanager created
  • following this, the plugin lifecycle points are called
  • all plugins, core and otherwise, are loaded at the same time
    • can specify with your own plugins if they should load explicitly before or after core plugins

Programming by Convention

  • every grails project has a set of conventions
  • configuration can be automated through conventions
  • grails supplies an API to inspect conventions via some key interfaces
    • GrailsApplication
    • GrailsClass

The GrailsApplication Interface

  • used for programming by convention
  • not an interface in the fixed Java term; dynamic object
  • inspect GrailsClass instances
  • extensible to new artefact types
  • available as a variable called application in plugins
  • interesting methods
    • Class[] getAllClasses() // gets all loaded classes
    • GrailsClass get*Class(String name) // gets a class by name
    • boolean is*Class(Class c) // checks if a class is of a given type
    • GrailsClass[] get*Classes() // all grailsclass instances of type
    • void add*Class(Class c)
    • all the * stuff in these examples are where you substitute the grails class type, e.g. getControllerClass(“fully.qualified.class.Name”)
  • can add new artefact handlers to add completely new artefact types to grails
    • can tell grails what the conventions are, e.g. “ends with X” or “lives in this directory”

Artefact Types

  • built in types
    • DomainClass
    • Controller
    • TagLib
    • Service
  • extensible to new by implementing ArtefactHandler

The GrailsClass Interface

  • allows you to further analyze conventions for each class
  • contains methods to get various forms of the class name
    • getShortName(): UserController (no package)
    • getPropertyName(): userController (bean name)
    • getNaturalName(): User Controller
    • others …
      • getLogicalPropertyName(), getPackageName(), etc.

Demo: Building a Technical Plugin

  • building an API to twitter
  • using twitter4j — twitter api for java
    • drop jar in lib directory of project
  • create a new public twitter bean in the doWithSpring plugin point
    • default constructor assumes public timeline
  • in doWithDynamicMethods are going to add ability for spring security users to submit to twitter
    • adding dynamic tweet() method to string class
    • String.metaclass.tweet = { ->
      def auth = SecurityContextHolder.context?.authentication
      if (auth instanceOf UsernamePasswordAuthenticationToken) {
      def twitter = new Twitter(auth.principal, auth.credentials)
      twitter.updateStatus(delegate)
      } else {
      throw new TwitterException(“user not logged in”)
      }
      }

Convention-Based Programming

  • have classes in the system, want to mark these as a “tweeter”
  • want to be able to call twitter methods to a user who’s marked as a tweeter
  • implement this in doWithDynamicMethods
  • inside each hook there is an implicit application keyword that represents the application context
    • application.domainClasses.each { GrailsDomainClass dc ->
      def metaClass = dc.metaClass
      metaClass.tweet = { String message ->
      def twitter = new Twitter(delegate.username, delegate.password)
      twitter.updateStatus(message)
      }

      metaClass.getLatestTweets = { ->
      def twitter = new Twitter(delegate.username, delegate.password)
      twitter.getPublicTimeline().text // property doesn’t exist but gpath automatically grabs text property of each object
      }
      }

Summary

  • more advanced knowledge of the grails plugin system opens up a world of possibilities
  • combine technical and functional plugins to enable new levels of productivity
  • harness the power of groovy metaprogramming!
  • helps avoid reinvention and duplication across applications

Q&A

  • inside any plugin you can do grails create-script and specify a gant script
    • used to extend the grails command line interface
  • plugins can provide different scaffolding templates to override the default ones and create your own uis
  • “plugins are the most important thing about grails”
  • any thoughts about how to eliminate bad/abandoned plugins from the central repository?
    • hudson build of all tests on all plugins done by a user
    • thoughts of integrating this into grails.org to give plugins a health status
  • plans to move plugins into git instead of SVN?
    • in grails 1.2 you can export plugin as a zip only so you can manage your source in git but still deploy to svn
    • complete move to git might be considered further down the line
  • SpringSource officially supports specific plugins

Session Notes – Grails Plugin System Part 1

Presenter: Graeme Rocher

Agenda

  • plugin quick start
  • technical vs. functional plugins
  • plugins for modularity
  • distribution and dependency management
  • plugin demo

Key Facts

  • grails itself is made up of a collection of plugins

    • hibernate, webflow, gsp, etc.
    • grails core is essentially a set of plugins (about a dozen)

  • there are 300+ plugins available now

    • what a plugin can do is wide and varied

  • plugins are easy to create

    • don’t need to spend a ton of time learning the internals of the framework to create a plugin

  • plugins are easy to distribute
  • everyone is a plugin developer
  • well over 25 million lines of user contributed code in the plugin repository

    • searchable

      • automatically makes any domain class searchable

    • taggable

      • adds apis to tag domain classes

    • rateable

      • ratings for domain classes

    • quartz

      • for scheduling tasks
      • interesting because it adds a new concept to grails — “jobs”
      • adds create-job command to command line, has a jobs directory, etc.

    • gwt
    • weceem cms

      • example of a functional plugin as opposed to just providing new apis
      • this plugin contains views, controllers, domains, etc. as part of the plugin

    • feeds (rss and atom feeds)
    • iwebkit (iphone)

Common Use Case

  • you have a tag library
  • you have two applications
  • you want to share functionality
  • create a plugin!
  • grails create-plugin pluginName creates the plugin skeleton
  • grails 1.2 creates intellij project files

Plugin Structure

  • more or less identical to a grails application structure
  • can run the plugins as standalone apps

    • developing a plugin is the same as developing an application

  • only real difference is there’s a plugin descriptor in the root of each plugin

    • contains info about plugin version, grails versions supported
    • can also exclude specific resources when the plugin is installed
    • also numerous plugin hooks that can be accessed (doWithWebDescriptor, doWithSpring, etc.)

  • using packages is important–should always uses packages in your applications

Plugin Quick Start — 5 steps

  • grails create-plugin myPlugin
  • cd myPlugin
  • grails create-tag-lib myTagLib
  • grails package-plugin
  • grails install-plugin

Plugin Extension Points

  • normal grails development

    • tag libraries, controllers, etc.
    • the build
    • theses are very trivial to do

  • requires additional knowledge

    • spring configuration
    • new apis

      • addition of additional properties/methods to domain classes and domain controllers

    • new concepts

Plugin Types

  • relate to the “split” above
  • functional plugins

    • taglibs, controllers, extend the build, etc.

  • technical plugins

    • see above–spring config, metaprogramming, etc.

Examples

  • functional plugins

    • weceem cms
    • nimble

      • provides user management, integration with facebook, etc.

  • technical plugins

    • gwt
    • functional test

  • both functional and technical

    • spring security
    • searchable

      • adds search to domain classes, but also provides a complete search UI to your application

Functional Plugins

  • easier to understand
  • just like building a normal grails application
  • silos of functionality

    • forums, blog, search, etc.

  • used to create modular applications

Demo: Building a Functional Plugin

  • example: twitter clone

    • two different teams–web UI team, mobile team
    • underlying functionality is the same

  • good candidate for a plugin–need to share the domain model between the two apps
  • can install plugins in other plugins

    • e.g. can install both the iwebkit and the twitter domain model plugin into the iphone version of the app
    • can specify plugins and versions in dependsOn block in the plugin descriptor
    • when you package up your plugin it will bundle up the plugins on which your plugin depends and include them

  • can use BootStrap.groovy within plugins
  • can configure local plugin repositories and can specify order in which plugin repositories are searched

Certain Things that Plugins Cannot Package by Default

  • BootStrap.groovy, UrlMappings.groovy, DataSource.groovy
  • can create something like FooUrlMappings.groovy and that will get packaged

Some Tips

  • inline plugins

    • if you’re modularizing your entire application, becomes impractical to repackage and reinstall every plugin as they change during development

  • url mappings
  • jar dependencies
  • testing
  • plugin distribution

Inline Plugins

  • use plugins without installing them
  • prevents package/install cycle
  • great for modular application development
  • go to grails-app/conf/BuildConfig.groovy and set grails.plugin.location.”pluginName”=”../path/to/plugin
  • BuildConfig.groovy

    • not generated automatically in 1.1.1
    • lets you configure various aspects of the build, locations of generated files, etc.

URL Mappings

  • normal UrlMappings.groovy file is excluded from the package plugin process
  • if you want to define url mappings as part of your plugin, create a file called something like MyPluginUrlMappings.groovy and that will be included

Plugin Dependencies

  • grails supports transitive installs and plugin dependencies using dependsOn
  • can use ranges of versions for dependencies, e.g. hibernate:”1.1 > *”
  • to implement a “soft” dependency use loadAfter

    • def loadAfter = [“hibernate”]
    • can also specify loadBefore

Plugin JAR Dependencies

  • you can put jar files in the lib directory of the project just like applications
  • even better, in grails 1.2 you can define dependencies in grails-app/conf/BuildConfig.groovy
  • grails.project.dependency.resolution = {
    inherits “global” // inherit grails’ default dependencies
    dependencies {
    runtime “org.apache.ant:ant:1.7.1”
    }
    }
  • different scopes can be involved–build, runtime, test, provided (needed during grails run-app but not during WAR deployment)
  • this means the jar files are NOT included in the plugin packaging

    • allows application into which the application is installed to resolve the dependencies

  • in a traditional java project, the jar dependency list is flat
  • in grails, you have dependencies of the app, of the framework, and of any plugins involved

Testing

  • done just like a normal application
  • sometimes it’s useful to have classes used only for testing and not distributed with the plugin
  • use pluginExcludes in the plugin descriptor to achieve this
  • class MyPlugin {
    def pluginExcludes = [
    “ant/path/here
    ]
    }

Plugin Distribution

  • central repository

    • grails release-plugin

  • custom repository

    • can configure custom repos in BuildConfig.groovy
    • can also set this in settings.groovy in your user home directory

  • Grails separates notion of repos used for discovery vs. distribution (e.g. http for discovery, https for distribution)
  • can specify the repository into which to release the plugin when you run grails release-plugin
  • custom repos use svn for distribution

    • can use a basic file server for discovery

  • plugins don’t necessarily have to be open source to be in the central repository

    • need to specify the license
    • would distribute jars instead of source

Summary

  • developing grails plugins is very simple
  • functional plugins are an easy way to modularize your application
  • in part 2 we’ll be looking at how to develop technical plugins

Q&A

  • as part of modularization is there any integration with osgi?

    • not yet, but looking into it–probably next year there will be something more concrete

  • are there particular plugins that you would highlight that follow best practices or as good models to follow?

    • depends on what you want to do
    • for a functional plugin check out weceem cms–complete end-to-end with views, js, etc.
    • for a technical plugin check out Build Test Data (creates mock data for you)
    • quartz plugin is a good example of a plugin that adds a new concept to grails, new command line arguments, etc.

      • exercises the artefact api

    • SpringWS plugin adds notion of an endpoint to Grails
    • Ratable, Commentable, Featurable, and Taggable are great examples of modifying domain classes on app load