Grails Filter at top of Filter Invocation Chain

27 / Jul / 2015 by Sandeep Poonia 0 comments

Sometimes in a web application we need filtering on request to a resource or on response, or on both. In Grails, it could be done easily via creating a filter. Just run grails create-filters [filter-name] and it will generate a filter in the application. To run a filter before all other filters, just put that filter at top of other filters in the class. If we have multiple filter classes defined then we can use dependsOn to specify that this filter depends upon other filters and they should be executed first.

[code lang=”groovy”]
class MyFilters{
def dependsOn=[HighPriorityFilters]
def filters= {
doSomething(uri:"/*"){
//logic
}
}
}

class HighPriorityFilters{
def filters={
doSomething(uri:"/*"){
//logic
}
}
}
[/code]

But this is only helpful only if application is not using any other plugins which use their own filters. To overcome this problem we would have to use Java EE filters along with some tweaks to web.xml.

Creating a Filter: Create a new groovy/java class under src directory in your application. Implement javax.servlet.Filter interface. Write your logic in doFilter() method.

Put it on top of Filter Chain: Java’s Filter order is defined in web.xml. To execute our newely created filter before all other filters we have two approaches:

1. Edit web.xml manually

To modify web.xml, first we need to download the scaffolding templates using grails install-templates. This command will download templates being used by Grails to generate different artifacts. We can find the web.xml template under src/templates/war/web.xml. If you will look into the web.xml file you will find filter mappings entries like this:

[code lang=”xml”]
<filter-mapping>
<filter-name>charEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
[/code]

You can add your own filter mapping just after the charEncodingFilter. Some plugins creates their filter just before the sitemesh filter but not all. They add their filters after the charEncodingFilter. Thus again defeating our purpose of executing our filter at top of the chain. It is strongly advised that don’t put your filter before charEncodingFilter. To solve this problem we would have to create a new plugin in our project.

2. Using Plugin

To create a plugin just run the command grails create-plugin [PLUGIN NAME]. Now open *GrailsPlugin.groovy file. Here you will find a closure with the name doWithWebDescriptor. Here we can declare our filter and define its mappings. Note that defining the mapping here will not effect the ordering in web.xml as webxml plugin is responsible for managing the ordering of filters in web.xml file. After adding your filter code in doWithWebDescriptor would look like this:

[code lang=”groovy”]
def doWithWebDescriptor = {
xml ->
def contextParam = xml.’context-param’
contextParam[contextParam.size() – 1] + {
‘filter’ {
‘filter-name'(‘myCustomFilter’)
‘filter-class'(com.ttnd.filter.MyFilterClass.name)
}
}

def filterMappings = xml.’filter-mapping’
// webxml plugin is responsible for filter mapping order. Put the filter mapping anywhere.
filterMappings[filterMappings.size() – 1] + {
‘filter-mapping’ {
‘filter-name'(‘myCustomFilter’)
‘url-pattern'(‘/*’)
‘dispatcher’ ‘REQUEST’
‘dispatcher’ ‘ERROR’
}
}
}
[/code]

Now we have to define the order of our filter. Add a method getWebXmlFilterOrder in this file. webxml plugin uses this method to identify the position of your filter in web.xml. Here is the code snippet:

[code lang=”groovy”]
def getWebXmlFilterOrder() {
log.debug("Start getWebXmlFilterOrder")
def filterMap = [:]
try {
def classLoader = new GroovyClassLoader(getClass().getClassLoader())
def FilterManager = classLoader.loadClass(‘grails.plugin.webxml.FilterManager’)
log.debug("set WebXmlFilterOrder after char encoding filter")
//grails.plugin.webxml.FilterManager class holds the position of default grails filters.
//Use this class to fetch the position of charEncodingFilter and put our filter just after that.
filterMap = [myCustomFilter: FilterManager.CHAR_ENCODING_POSITION]
} catch (ClassNotFoundException e) {
log.error "Could not determine desired nimbusFilter position."
}
return filterMap
}
[/code]

Now you would be asking to yourself that aren’t other plugins use same method to put their filter just after the charEncodingFilter.
Yes, you are right. They do follow the same method. So how can we put our filter before their filter?

Answer is loadAfter. You will find a variable declared with name loadAfter within the same plugin file. Here we can add the artifact names or plugin names after which we want our plugin methods to execute. So if you are using shiro plugin for security purpose, you would add its name to this field. Here is a code snippet:

[code lang=”groovy”]
def loadAfter = [
‘hawk-eventing’,
‘hibernate-hijacker’,
‘shiro’,
‘core’,
‘dataSource’
]
[/code]

That’s all. Now your filter will be invoked first in filter chain. Cheers!!!

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *