views:

1577

answers:

2

Grails provides filters that run before your controllers. They're defined in classes that look like this:

class SecurityFilters {
   def filters = {
       myFilter(controller:'*', action:'*') { // What are those weird colons??
           print "I'm filtering!"
           // Code that does the filtering goes here
       }
   }
}

These work great but I would like to understand the syntax better as it doesn't look like any Groovy code I've seen before. In particular, the line above that starts with myFilter seems very odd. Is this a method definition for a method called myFilter? If so, what does :'*' mean after each parameter? I thought it might be a default parameter value but that would be ='*'. I've seen named parameters using colons in method calls before but this couldn't be a method call because I haven't defined myFilter() anywhere else.

I think I'd understand much better if someone could just tell me how to execute the filtering code from a normal Groovy class. In other words, if I have a file MyFilters.groovy that contains the lines above, how could I finish this Groovy code so it prints "I'm filtering"?

import MyFilters
def mf = new MyFilters()
mf.filters.somethingGoesHere // Help! How do I finish this line so it calls my filtering code?
A: 

You can't easily call filters outside of grails because they depend on a lot of plumbing that won't be set up. The line
myFilter(controller:'', action:'')
is a method definition that takes two arguments, a controller and action pattern. * means apply this filter to any object of the proceeding type. For example if we wanted to make sure users couldn't create anything unless they were authorized we would use the following filter.
controller:'*', action:'create'
This would mean that any time a create action was called the code stored in that function body would execute, but for list, show, or edit no filter would execute. If you really want detail you can always download the grails source code.
edit:
The code compiles since it's a function defined in a filter.

Jared
Thanks - I know how filters and their controller and action patterns work within Grails. But I would like to know why the MyFilter code shown above is legal Groovy. It compiles but I can't work out why!
Douglas Squirrel
+3  A: 

The following Groovy code would print "I'm filtering!":

class SecurityFilters {
   def filters = {
       myFilter(controller:'*', action:'*') { // What are those weird colons??
           print "I'm filtering!"
           // Code that does the filtering goes here
       }
   }   
}

class FilterDelegate {
    def methodMissing(String methodName, args) {
        // methodName == myFilter
        // args[0] == [controller:*, action:*]
        // args[1] == {print "I'm filtering!"}
        args[1].call()
    }
}

def sf = new SecurityFilters()
def filtersClosure = sf.filters
filtersClosure.delegate = new FilterDelegate()
filtersClosure.call()

In this example filters is a closure that calls a method named myFilter and passes a map and a closure. You can think of myFilter as:

myFilter([controller:'*', action:'*'], closure)

The Map can contains keys like controller, action or uri. The wildcard (*) is used when Grails attempts to match the URI from the HTTP request when it tries to determine which closure to call.

My understanding of how Grails handles filters is that a delegate loader class is used. The loader class provides a methodMissing method and creates a FilterConfig for each method call inside the filters closure. When a HTTP request is made, Grails looks through all the FilterConfig objects and tries to find a matching scope (looks in the map for a controller, action or uri and uses regexs to match on wildcards). If it finds a match it calls the closure that was passed into the method in the Filter class.

John Wagenleitner
Great explanation - thanks!
Douglas Squirrel