Monday 11 February 2008

My first Grails plugin

The grails plugin architecture it's fantastic, I've spent one afternoon doing a static content plugin, yeah there is a oficial static plugin, but I use jetty for development and production, and the static content it's uploaded by the users.
With Jetty servlet to server static content is enought for me, and with some configuration parameters, if required can be disabled.

Another advantage is that this way you can protect your static content with the Acegi plugin.

The first step it's create plugin:
grails create-plugin jettystatic
The project looks like a normal grails project, excepts that you have a plugin descriptor file.
In the JettystaticGrailsPlugin.groovy I've updated the web.xml generated:

def doWithWebDescriptor = { webXml ->
log.info "Jetty Static Initializing servlet"
def dir = application.config?.jettystatic.dir
if(!dir){
dir = './static'
}

if(application.config?.jettystatic.ignore){
log.info "Jetty Static: No jetty static servlet inicialized"
return
}

log.info "Jetty Static dir '${dir}' and mapping '${mapping}'"
def mapping = '/resources/*'
def servlets = webXml.'servlet'

servlets[servlets.size()-1] + {
'servlet' {
log.info 'Jetty Static generating <servlet> for static content'

'servlet-name'("jettystatic")
'servlet-class'("org.mortbay.jetty.servlet.DefaultServlet")

'init-param' {
'param-name'("resourceBase")
'param-value'(dir)
}

'init-param' {
'param-name'("dirAllowed")
'param-value'("false")
}

'init-param' {
'param-name'("gzip")
'param-value'("true")
}

'load-on-startup'("1")
}
}

def mappings = webXml.'servlet-mapping'
mappings[mappings.size()-1] + {
'servlet-mapping' {
'servlet-name'("jettystatic")
'url-pattern'(mapping)
}
}
}
The other thing I need, is a taglib to make links to static content, and I'd like that the tag transform from absolute path of static content to a relative web path, this make easy upload content, and server the content uploaded.

def resource = {attrs ->
def url = grailsApplication.config?.jettystatic.absolute.url
def dir = grailsApplication.config?.jettystatic.basepath
def file = attrs.file
def baseUrl = ""

if(dir){
if(!dir.endsWith('/')){
dir = dir + '/'
}
file = file.replaceFirst(dir,"")
}
if(url){
baseUrl = url
}else{
baseUrl = g.createLinkTo(dir:'resources')
}

def env = GrailsUtil.environment
if(env && env == "development"){
baseUrl = g.createLinkTo(dir:'resources')
}


if(!baseUrl.endsWith('/')){
baseUrl = baseUrl + '/'
}
out<< "${baseUrl}${file}"
}
At this point the only thing I have to do is package my plugin (grails package-plugin) to use in any project.

I can't imagine doing something like this in java and spend this time.

5 comments:

olope said...

Congratulations David! good job.

Nils Kassube said...

Hi,
nice one. One note: you can use -1 to address the element at the end of a list, no need for the Java-esque foo.size()-1 expression.

Cheers,
Nils Kassube

dahernan said...

Good note, thanks

Anonymous said...

This is exactly what I've been looking for!

As a Grails noob, would you be able to shed some light on using this in a project?

dahernan said...

http://code.google.com/p/jettystatic/wiki/Usage