The Kaptain on … stuff

16 Dec, 2009

Jira Grails Plugin

Posted by: TheKaptain In: Development

I set out to explore some of the Atlassian API’s this week, along with a test drive of Jira 4, and ended up developing a simple XML-RPC plugin for Grails. Utilizing little more than the Groovy XMLRPC library I was able to implement a client service for the Jira XmlRpcService in minutes.

Nothing terribly complicated going on for this plugin. Aside from the XMLRPC library and one more jar it depends upon there’s a service which implements calls for all of the methods on the XmlRpcService interface and a ‘helper’ class that makes using it a little easier(removes the need to pass the host name into each method). And any controller injected with the service gets a withJira(hostname, Closure) method which wraps the ‘helper’ class. This might not be the optimal way to do things, but I was looking for some better experience with MOP’ing in Groovy along with this little project so it worked out perfectly for me.

The method added to Controller classes just creates a ‘helper’ and sets it as the delegate for the closure.

        cClass.metaClass.withJira = {String hostname, Closure closure ->
            def helper = delegate.jiraXmlRpcService.createHelper(hostname)
            closure.setDelegate(helper)
            closure.setResolveStrategy(Closure.DELEGATE_FIRST)
            closure()
        }

Calling the withJira method looks like this, along with minimal exception handling:

            try
            {
                def projects, priorities, serverInfo
                withJira(jiraInstance.baseUrl) {
                    def token = login(jiraInstance.userName, jiraInstance.password)
                    serverInfo = getServerInfo(token)
                    priorities = getPriorities(token)
                    projects = getProjectsNoSchemes(token)
                    logout(token)
                }
                [jiraInstance: jiraInstance, projects: projects, priorities: priorities, serverInfo: serverInfo]
            }
            catch (e)
            {
                flash.message = "Failed to load data from ${jiraInstance.baseUrl}"
                redirect(action: "list")
            }

The ‘helper’ class itself represents an experiment with the Groovy ‘methodMissing’ behaviour. The idea is to store the ‘hostname’ for a series of calls against the stateless service and add that as the first parameter for all wrapped methods. It was simple and quick, but right off the bat you lose the ability to use IDE syntax completion support on this object. I thought another possibility here would be to use the @Delegate annotation on the service and/or Closure currying to add the additional ‘hostname’ parameter to methods.

class JiraXmlRpcServiceHelper
{
    def hostname
    def JiraXmlRpcService service

    def methodMissing(String name, args)
    {
        assert hostname && service
        def method = service.metaClass.methods.find {it.name == name}
        if(!method)
        {
            throw new NotImplementedException("The $name method is not implemented for ${this.getClass()}")
        }

        def newArgs = [hostname]
        args.each{newArgs << it}
        return method.invoke(service, newArgs as Object[])
    }
}

This plugin works with Grails 1.2.0.RC1 and represents about 8 hours of work all told – and a lot of fun to make! Jira 4 is not too shappy either, especially with the GreenHopper plugin. But that’s a post for another day.

A special thank you to Grails in Action and this article by Ted Naleid – both were extremely helpful putting this together. If you care to download it and take a spin here it is. Feedback is always welcome!

[download id=”1″]

Reblog this post [with Zemanta]
Share

About

Tales of development, life and the folly that goes along with both.

Tags

profile for TheKaptain at Stack Overflow, Q&A for professional and enthusiast programmers
Get Adobe Flash player