Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
239 lines (176 sloc) 6.2 KB

Interceptors

ActFramework support creating interceptor in two different ways:

  1. Annotation based interception method (PlayFramework style)
  2. Api based interceptor

Annotation based interceptor

The idea of annotation based interceptor is completely borrowed from PlayFramework 1.x.

Before

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.

@After

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);
    }

    …
}

@Catch

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);
    }
}

@Finally

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);
    }
    …
}

Controller hierarchy

If a Controller class is a subclass of another Controller class, interceptions are applied to the full Controller hierarchy.

Adding more interceptors using the @With annotation

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 {

    …
}

Inheritant from XxxInterceptor

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:

  1. act.handler.builtin.controller.AfterInterceptor
  2. act.handler.builtin.controller.ExceptionInterceptor
  3. act.handler.builtin.controller.FinallyInterceptor

Back to index