Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails filter syntax, or, How to call a Grails Filter outside Grails

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?
like image 643
Douglas Squirrel Avatar asked Aug 10 '09 14:08

Douglas Squirrel


1 Answers

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.

like image 87
John Wagenleitner Avatar answered Sep 29 '22 01:09

John Wagenleitner