ActFramework support creating interceptor in two different ways:
- Annotation based interception method (PlayFramework style)
- Api based interceptor
The idea of annotation based interceptor is completely borrowed from PlayFramework 1.x.
Methods annotated with the @Before annotation are executed before each action call for this Controller.
So, to create a security check:
public class Admin extends Controller.Util {
@Before
public void checkAuthentification() {
if(session.get("user") == null) {
redirect("/login");
}
}
public void index() {
Iterable<User> users = userDao.findAll();
render(users);
}
…
}If you don’t want the @Before method to intercept all action calls, you can specify a list of actions to exclude:
public class Admin extends Controller.Util {
@Before(except="login")
static void checkAuthentification() {
if(session.get("user") == null) {
redirect("/login");
}
}
public void index() {
Iterable<User> users = userDao.findAll();
render(users);
}
…
}Or if you want the @Before method to intercept a list of action calls, you can specify a only param :
public class Admin extends Controller.Util {
@Before(only={"login","logout"})
public void doSomething() {
…
}
…
}The except and only parameters are available for the @After, @Before and @Finally annotations.
Methods annotated with the @After annotation are executed after action handler call for this Controller.
public class Admin extends Controller.Util {
@After
public void log() {
Logger.info("Action executed ...");
}
public void index() {
Iterable<User> users = userDao.findAll();
render(users);
}
…
}Methods annotated with @Catch are called if another action method throws the specified exception. The thrown exception is passed as a parameter to the @Catch method.
public class Admin extends Controller.Util {
@Catch(IllegalStateException.class)
public void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public void index() {
List<User> users = userDao.findAllAsList();
if (users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}As with normal Java exception handling, you can catch a super-class to catch more exception types. If you have more than one catch method, you can specify their priority so that they are executed in order of priority (priority 1 is executed first).
public class Admin extends Controller.Util {
@Catch(value = Throwable.class, priority = 1)
public void logThrowable(Throwable throwable) {
// Custom error logging…
Logger.error("EXCEPTION %s", throwable);
}
@Catch(value = IllegalStateException.class, priority = 2)
public void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public void index() {
List<User> users = userDao.findAllAsList();
if(users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}Methods annotated with the @Finally annotation are always executed after each action call to this Controller.
@Finally-methods are called both after successful action calls and if an error occurred.
public class Admin extends Controller.Util {
@Finally
static void log() {
Logger.info("Response contains : " + response.out);
}
public static void index() {
List<User> users = userDao.findAllAsList();
render(users);
}
…
}If a Controller class is a subclass of another Controller class, interceptions are applied to the full Controller hierarchy.
Because Java does not allow multiple inheritance, it can be very limiting to rely on the Controller hierarchy to apply interceptors. But you can define some interceptors in a totally different class, and link them with any controller using the @With annotation.
Example:
public class Secure extends Controller.Util {
@Before
static void checkAuthenticated() {
if(!session.containsKey("user")) {
unAuthorized();
}
}
} And on another Controller:
@With(Secure.class)
public class Admin extends Controller.Util {
…
}Annotation based interceptor is very handy to write interception logic that local to a certain controller or a group of controllers. However if you have interception logic that should be applied to all controllers, you need to inherit from XxxInterceptors
import act.app.ActionContext;
import act.handler.builtin.controller.BeforeInterceptor;
import act.plugin.Plugin;
import org.osgl.http.H;
import org.osgl.mvc.result.Result;
import javax.inject.Singleton;
@Singleton
public class MockRequestContentAcceptor extends BeforeInterceptor {
public MockRequestContentAcceptor() {
super(1);
Plugin.InfoRepo.register(this);
}
@Override
public Result handle(ActionContext actionContext) throws Exception {
String s = actionContext.paramVal("fmt");
if ("json".equalsIgnoreCase(s)) {
actionContext.accept(H.Format.JSON);
} else if ("csv".equalsIgnoreCase(s)) {
actionContext.accept(H.Format.CSV);
} else if ("xml".equalsIgnoreCase(s)) {
actionContext.accept(H.Format.XML);
}
return null;
}
}The above code implement a logic that will be called before everytime invoking an action handler. There are similar Interceptor base classes including:
act.handler.builtin.controller.AfterInterceptoract.handler.builtin.controller.ExceptionInterceptoract.handler.builtin.controller.FinallyInterceptor
