Fork me on GitHub

17 Mar 2010

Customising collection binding in Grails

Following up on my earlier post about using custom PropertyEditor implementations to bind association properties I started looking into the options for custom binding one-to-many associations.

For example, tags, as seen on many sites (including Blogger) would typically be modelled as a Set of either String or some kind of Tag domain object. With tag functionality we really don't want to be selecting tags using a multi-select combo box. It would be ridiculously huge and hard to find anything in it. An auto-completer that recognises commas as delimiters would be the way to go. Script.aculo.us has an AJAX Autocompleter that can handle this kind of tokenised input. Similarly, the Grails RichUI plugin offers an autocomplete tag that uses a Yahoo! UI component. There are comparable controls available if you're using jQuery or some other Javascript library. What you will end up with is the browser submitting a single parameter containing a comma-separated String of tag names. The trick is to turn that into a collection of String or Tag domain instances.

For the former case binding is pretty easy. All you need is a property editor that converts a comma-separated String into a Set of String and vice-versa:
Then just register the editor in your PropertyEditorRegistrar implementation:
registry.registerCustomEditor List, "tags", new TagListEditor()

If you've gone the latter route and used a domain object to represent a tag things have been trickier. Grails didn't allow you to register custom property editors against one-to-many association properties as it considered it knew how to handle such binding.

I raised and fixed a Grails issue to allow for registering custom editors on one-to-many properties so from 1.2.2 and 1.3-M2 you will be able to use a property editor something like this:

11 Mar 2010

Grails plugins on Hudson

Yesterday I spent some time setting up Hudson continuous integration build for my various Grails plugins. It was pretty straightforward but I've been asked to document the steps involved.

Each plugin has one or more test applications under test/projects each of which has grails.plugin.location.whatever = "../../.." in BuildConfig.groovy. So each plugin CI build needs to run not only the plugin's own unit tests but any integration and/or functional tests included in the test apps as well.

Hudson plugins

I installed the essential plugins I would need:
  • The Grails plugin makes building Grails projects much easier and allows you to build against multiple versions of Grails.
  • The Git plugin enables Hudson to pull from a Git repository such as GitHub.
  • The GitHub plugin adds links to the GitHub project in the Hudson build.
  • The Chuck Norris plugin encourages you to keep your tests from failing.

Configuring Grails

Under Manage Hudson -> Configure System there is a Grails Builder section where I entered the name and path of the various versions of Grails installed on the build box.

Connecting to GitHub

In the project configuration:
  • I pasted the GitHub project URL in the Github project field (shown if you have the GitHub plugin installed).
  • Under Source Code Management I selected Git then pasted the read-only repository URL into the URL of repository field.
  • I entered master in the Branch Specifier field as I've seen Hudson do odd things picking up changes from other branches before. I don't really need this behaviour and haven't had time to investigate it further yet.
  • I ticked Poll SCM under Build Triggers then set a cron expression of */5 * * * * so Hudson will poll GitHub every 5 minutes.

Grails build steps

  • Select Build with Grails from the Add build step drop down, then:
    • Select the Grails Installation you want to use.
    • Enter the Targets to run. These are the Grails commands that Hudson will execute. For example, I entered "test-app unit: -clean --non-interactive" package-plugin for the to run unit tests then package the plugin. The quotes allow arguments to be passed to individual targets so I'm telling the test-app phase to build clean and run non-interactively (i.e. Grails won't ask about things like installing or uninstalling plugins).
    • The other fields can be left blank for now.
  • Add further Grails build steps for test applications. The only difference in configuring these is that the targets will likely be different and Project Base Directory needs to be set to the relative path where the test apps lives, e.g. test/projects/content-caching

Isolating each build

One thing I found is that it's probably a good idea to specify separate working directory for each build. I found that simultaneous builds would stomp over each other's compiled classes otherwise. This is particularly an issue for me where I have a build for the Selenium RC plugin whilst one of the test apps for the Springcache plugin uses the latest Selenium RC release to run tests.

Hudson provides various environment variables so I just set grails.work.dir to /tmp/.grails/${JOB_NAME} in every case.

The other consideration is the port that Grails applications will use. If you are running any kind of functional tests the Grails application will start and it each Hudson job needs to use a separate server port or simultaneous jobs will experience port contention. The server port is also configured in the Grails build step. I've just assigned a different one to each job but I couldn't think of a particularly clever way to automate the port assignment.

Test reports

Under Post-build Actions I ticked Publish JUnit test result report then entered a comma-separated set of paths to the XML reports generated by each build step. For example, the Springcache plugin has the following reports configured:
target/test-reports/*.xml,test/projects/springcache-test/target/test-reports/*.xml,test/projects/content-caching/target/test-reports/*.xml

That's picking up the root plugin's unit test reports and the reports generated by the springcache-test and content-caching test applications. Hudson does a good job of merging these together into a unified test report.

Running tests that need a browser

Some of my tests use Selenium RC which drives a real browser. Given that Hudson is running on a headless box I had to get the display exported to a box with an X Windows environment.

Still to do

Right now all the plugins are building against Grails 1.2.1 only so the next task is to set up parallel builds using Grails 1.3-RC1. Ideally I would like to use Hudson's multi-configuration project capability to do that but I haven't had a chance to look into it yet. I'd also like to use Gradle to build the various project with one build step but I'd lose the convenience in switching Grails versions that the Hudson Grails plugin gives me.

5 Mar 2010

Page fragment caching with Grails Springcache plugin

Yesterday I released the new version of the Springcache plugin for Grails. The new feature this brings to the table is page fragment caching driven by annotations on controller actions. The feature is based on EhCache Web and is even simpler and more powerful than the full page caching I blogged about recently. With the page fragment caching feature you can:

  • Define @Cacheable and @CacheFlush annotations on controller actions.
  • Have SiteMesh decorate cached and uncached output alike.
  • Use SiteMesh to mix dynamic page sections with cached sections.
  • Use SiteMesh and <g:include> to have multiple areas of the page that are cached and flushed independently of one another.
  • Cache the output of controller actions that use content negotiation separately according to the requested format.

There are some examples in the plugin documentation and the plugin source code has a test project with a variety of page fragment caching mechanisms used and tested.