org.apache.click
Interface PageInterceptor


public interface PageInterceptor

Provides a Page life cycle interceptor. Classes implementing this interface can be used to listen for key page life cycle events and abort further page processing if required.

PageInterceptors can be used for many different purposes including:

A Click application can define multiple page interceptors that are invoked in the order in which they are returned by the ConfigService.

Scope

Page interceptors can be defined with a request level scope, whereby a new page interceptor will be created with each page request providing a thread safe programming model.

Please note, as new interceptor instances are created with each request, care should be taken to ensure that these objects are light weight and do not introduce a performance bottleneck into your application.

Alternatively, page interceptors can be defined with application level scope whereby a single instance is created for the application and is used for all requests.

Note application scope interceptors are more efficient that request scope interceptors, but you are responsible for ensuring that they are thread safe and support reentrant method invocations as multiple page requests are processed at the same time.

Configuration

Application PageInterceptors are configured in the click.xml configuration file. PageInterceptors must support construction using a no-args public constructor.

Page interceptors can have multiple properties configured with their XML definition which are set after the constructor has been called. Properties are set using OGNL via PropertyUtils.

An example configuration is provided below:

 <page-interceptor classname="com.mycorp.PageSecurityInterceptor" scope="application">
     <property name="notAuthenticatedPath" value="/not-authenticated.htm"/>
     <property name="notAuthorizedPath" value="/not-authorized.htm"/>
 </page-interceptor> 
The default scope for page interceptors is "request", but this can be configured as "application" as is done in the example configuration above.

Example

 public class SecurityInterceptor implements PageInterceptor {

    // The request not authenticated redirect path.
    private String notAuthenticatedPath;

    // The request not authorized redirect path.
    private String notAuthorizedPath;

    // Public Methods ---------------------------------------------------------

    public boolean preCreate(Class pageClass, Context context) {

       // If authentication required, then ensure user is authenticated
       Authentication authentication = pageClass.getAnnotation(Authentication.class);

       // TODO: user context check.

       if (authentication != null && authentication.required()) {
          sendRedirect(getNotAuthenticatedPath(), context);
          return false;
       }

       // If authorization permission defined, then ensure user is authorized to access the page
       Authorization authorization = pageClass.getAnnotation(Authorization.class);
       if (authorization != null) {
          if (!UserContext.getThreadUserContext().hasPermission(authorization.permission())) {
             sendRedirect(getNotAuthorizedPath(), context);
             return false;
          }
       }

       return true;
    }

    public boolean postCreate(Page page) {
       return true;
    }

    public boolean preResponse(Page page) {
       return true;
    }

    public void postDestroy(Page page) {
    }

    public String getNotAuthenticatedPath() {
       return notAuthenticatedPath;
    }

    public void setNotAuthenticatedPath(String notAuthenticatedPath) {
       this.notAuthenticatedPath = notAuthenticatedPath;
    }

    public String getNotAuthorizedPath() {
       return notAuthorizedPath;
    }

    public void setNotAuthorizedPath(String notAuthorizedPath) {
       this.notAuthorizedPath = notAuthorizedPath;
    }

    // Protected Methods ------------------------------------------------------

    protected void sendRedirect(String location, Context context) {
       if (StringUtils.isNotBlank(location)) {
          if (location.charAt(0) == '/') {
             String contextPath = context.getRequest().getContextPath();

             // Guard against adding duplicate context path
             if (!location.startsWith(contextPath + '/')) {
                location = contextPath + location;
             }
          }
       }

       location = context.getResponse().encodeRedirectURL(location);

       try {
          context.getResponse().sendRedirect(location);

       } catch (IOException ioe) {
          throw new RuntimeException(ioe);
       }
   }
 } 
 // Page class authentication annotation
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Authentication {
    boolean required() default true;
 } 
 // Page class authorization annotation
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Authorization {
    String permission();
 }
 


Method Summary
 boolean postCreate(Page page)
          Provides a post page object creation interceptor method, which is passed the instance of the newly created page.
 void postDestroy(Page page)
          Provides a post page destroy interceptor method.
 boolean preCreate(Class<? extends Page> pageClass, Context context)
          Provides a before page object creation interceptor method, which is passed the class of the page to be instantiated and the page request context.
 boolean preResponse(Page page)
          Provides a page interceptor before response method.
 

Method Detail

preCreate

boolean preCreate(Class<? extends Page> pageClass,
                  Context context)
Provides a before page object creation interceptor method, which is passed the class of the page to be instantiated and the page request context. If this method returns true then the normal page processing is performed, otherwise if this method returns false the page instance is never created and the request is considered to have been handled.

Parameters:
pageClass - the class of the page to be instantiated
context - the page request context
Returns:
true to continue normal page processing or false whereby the request is considered to be handled

postCreate

boolean postCreate(Page page)
Provides a post page object creation interceptor method, which is passed the instance of the newly created page. This interceptor method is called before the page Page.onSecurityCheck() method is invoked.

If this method returns true then the normal page processing is performed, otherwise if this method returns false the request is considered to have been handled.

Please note the page Page.onDestroy() method will still be invoked.

Parameters:
page - the newly instantiated page instance
Returns:
true to continue normal page processing or false whereby the request is considered to be handled

preResponse

boolean preResponse(Page page)
Provides a page interceptor before response method. This method is invoked prior to the page redirect, forward or rendering phase.

If this method returns true then the normal page processing is performed, otherwise if this method returns false request is considered to have been handled.

Please note the page Page.onDestroy() method will still be invoked.

Parameters:
page - the newly instantiated page instance
Returns:
true to continue normal page processing or false whereby the request is considered to be handled

postDestroy

void postDestroy(Page page)
Provides a post page destroy interceptor method. This interceptor method is called immediately after the page Page.onDestroy() method is invoked.

Parameters:
page - the page object which has just been destroyed