...and (why || how) they can be your friend.
Useless Preamble
As previously mentioned, I’ve been using Spring a whole lot in the ‘latest project’, and in addition am using Acegi Security to provide authentication and authorization services.
Scenario
Now that all that is out of the way, I, like most other people who write webapps, wanted a way to display the currently logged in users information on the screen for them. You know, username, maybe a “Hello, $USERNAME! Thanks for coming out!” type nonsense. So in Acegi, the code used to get the currently logged in user looks like this:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Once you’ve got the Authentication object, you need to get the Principal, which will at last be castable into whatever your User object implementation happens to be. So basically for me, I had a getUser() method that looks like this:
protected User getUser(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if ( auth != null && auth.getPrincipal() instanceof User ){
return (User) auth.getPrincipal();
} else {
return null;
}
The Problem
Now, this is all well and good, and in Spring, chances are you want to add this code to a Controller implementation somewhere. But which Controller? I’ve got a ton of them. I thought of extracting it to some superclass, but based on the Spring controller hierarchy, whereby sometimes you might extend AbstractController, or SimpleFormController, or implement the Controller interface directly, it didn’t seem like this was going to cut the cake, so to speak. We don’t have multiple inheritance in Java (duh!), so I couldn’t do that, and I certainly didn’t feel like putting the code in some separate bean that I would have to inject into every single one of my controllers. Oh what to do?
The Solution
Enter interceptors. Oh how we love thee (when they’re the appropriate tool for the job).
So, an interceptor basically does exactly what it says it does. It “intercepts” method calls to an object. For all the details, go read something about AOP, this is just going to be an example in somewhat plain English.
In my particular case, I wanted to “intercept” all calls to the handleRequest(...) methods of the org.springframework.web.servlet.mvc.Controller interface (which all Spring controllers implement). If I could do that, then any time a method was intercepted, I could simply call my neat little getUser() method and dump the user into the current HttpServletRequest as an attribute. Spot on!1
So um, how the heck to we actually do it? Ok, first of all, let’s write the actual interceptor class. This is the class that we want to be automagically called any time the handleRequest(...) method of a Controller is executed (I’ve gotten rid of comments and imports).
public class AddUserToModelInterceptor implements MethodInterceptor { public Object invoke( MethodInvocation methodInvocation ) throws Throwable {
ModelAndView model = (ModelAndView) methodInvocation.proceed();
if ( model != null && getUser() != null ){
model.addObject( "user", getUser() );
}
return model;
} protected User getUser(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if ( auth != null && auth.getPrincipal() instanceof User ){
return (User) auth.getPrincipal();
} else {
return null;
}
}
}
Note that the fully qualified class name (in case you’re curious) of MethodInterceptor is org.aopalliance.intercept.MethodInterceptor
Great, so we have an interceptor, now what? Lets go define some beans!
<bean id="addUserToModelInterceptor"
class="com.example.AddUserToModelInterceptor"/> <bean id="controllerClassFilter" class="com.example.ControllerClassFilter"/> <bean id="controllerPointCutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="classFilter" ref="controllerClassFilter"/>
<property name="advice" ref="addUserToModelInterceptor"/>
<property name="mappedName" value="handleRequest"/>
</bean> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
Alright, the first bean definition is just an instance of the AddUserToModelInterceptor that we just finished showing in the above example. After that, we have a class filter (which we’ll look at in a second). Thirdly there is the bean controllerPointCutAdvisors. Joins, Pointcuts and Advice are fancy AOP terminology that you should really read about, but I won’t cover here. We pass three simple properties to this bean. The first is just the class filter, the second is the “Advice” which is a reference to our interceptor bean, and lastly, we pass “mappedName” – which is simply the method name that we would like to intercept calls to, in our case, “handleRequest”. Lastly, we define a proxy creator bean, which in this case is an instance of Spring’s DefaultAdvisorAutoProxyCreator. Basically, what this bean does is once all of the bean definitions have been loaded, it scours all loaded beans applying advice to matching pointcuts. In our case, it will apply our “addUserToModelInterceptor” advice to all bean instances that match our “classFilter” that have the method name “handleRequest”.
Briefly, the class filter is just a dead simple interface that Spring offers. In essence, we don’t want our advice to be applied to any classes that ‘accidentally’ define a method called handleRequest. We only want the advice applied to classes that implement Spring’s Controller interface. So here is what our ControllerClassFilter looks like:
public class ControllerClassFilter implements ClassFilter {
public boolean matches( Class aClass ) {
return Controller.class.isAssignableFrom( aClass );
}
}
Fewf! Something easy to end off with!
I hope that this has managed to help shed a little light on how interceptors can be useful, and hopefully some of it actually made sense.