Understanding AtmosphereInterceptor

tehnicaorg edited this page Jan 15, 2014 · 14 revisions

FAQ

Step by Step Tutorials

Concepts & Architecture

15 Minutes Tutorial

Advanced Topics

API

Known WebServer Issues

References

External Documentations

githalytics.com alpha

Clone this wiki locally

The framework ships with several implementation of AtmosphereInterceptor. Interceptors are called before and after AtmosphereHandler. You can define AtmosphereInterceptors that apply to all AtmosphereHandlers by annotating them using:

 @AtmosphereInterceptorService

or per Meteor or AtmosphereHandler using

 @MeteorService(interceptors={...})

 @AtmosphereHandlerService(interceptors={...})  

You can also define them in web.xml/atmosphere.xml

   // web.xml
   <init-param>
      <param-name>org.atmosphere.cpr.AtmosphereInterceptor</param-name>
      <param-value>list of classes</param-value>
   </init-param>

   // application.xml
   <applicationConfig>
      <param-name>org.atmosphere.cpr.AtmosphereInterceptor</param-name>
      <param-value>list of classes</param-value>
   </applicationConfig>

or per AtmosphereHandler in atmosphere.xml

<atmosphere-handler 
    support-session="true"
    context-root="/*" class-name="..."
    broadcaster="..."
    broadcasterCache=""
    broadcastFilterClasses=""
    interceptorClasses=""
    comet-support=""
>

AtmosphereInterceptor allows an application to customize the request/response before they get delivered to the AtmosphereHandler. Atmosphere ships with several implementation and some of them are installed by default, when you deploy your application.

Reducing the lines of code in your application

Without interceptor, an AtmosphereHandler would look like

@AtmosphereHandlerService(path="/chat")
public class ChatAtmosphereHandler implements AtmosphereHandler {

    @Override
    public void onRequest(AtmosphereResource r) 
           throws IOException {

        AtmosphereRequest req = r.getRequest();
        // First, tell Atmosphere
        // to allow bi-directional communication by suspending.
        if (req.getMethod().equalsIgnoreCase("GET")) {
                r.suspend();
        // Second, broadcast message to all connected users.
        } else if (req.getMethod().equalsIgnoreCase("POST")) {
            r.getBroadcaster().broadcast(req.getReader().readLine().trim());
        }
    }

    @Override
    public void onStateChange(AtmosphereResourceEvent event) 
            throws IOException {
        AtmosphereResource r = event.getResource();
        AtmosphereResponse res = r.getResponse();

        if (event.isSuspended()) {
            ...

            switch (r.transport()) {
                case JSONP:
                case AJAX:
                case LONG_POLLING:
                    event.getResource().resume();
                    break;
                default:
                    res.getWriter().flush();
                    break;
            }
        } 
    }

Now let the framework manage the AtmosphereResource:

@AtmosphereHandlerService(path = "/chat", interceptors=
{AtmosphereResourceLifecycleInterceptor.class})
public class SocketIOChatAtmosphereHandler implements AtmosphereHandler {

    @Override
    public void onRequest(AtmosphereResource r) 
           throws IOException {
        r.getBroadcaster().broadcast(r.getRequest().getReader().readLine());
    }

    @Override
    public void onStateChange(AtmosphereResourceEvent event) 
           throws IOException {
        AtmosphereResource r = event.getResource();
        AtmosphereResponse res = r.getResponse();

        if (event.isSuspended()) {
            .....
        }
    }

Better, if you don't want to handle the broadcast operation as well, just do:

@AtmosphereHandlerService(path = "/chat", interceptors= 
{AtmosphereResourceLifecycleInterceptor.class,
 BroadcastOnPostAtmosphereInterceptor.class})
public class SocketIOChatAtmosphereHandler implements AtmosphereHandler {

    @Override
    public void onRequest(AtmosphereResource r) 
       throws IOException {
    }

    @Override
    public void onStateChange(AtmosphereResourceEvent event) 
           throws IOException {
        AtmosphereResource r = event.getResource();
        AtmosphereResponse res = r.getResponse();

        if (event.isSuspended()) {
            .....
        }
    }

AtmosphereInterceptor order invocation

By default, an AtmosphereInterceptor is added at the end of the interceptor's list, and will be executed after the default interceptors has been executed. If your interceptor must be execute before default, or the first after the default, all you need to do is to implements the InvokerOrder with your AtmosphereInterceptor. InvokerOrder is defined as:

public interface InvokationOrder {

    enum PRIORITY {
        /**
         * The AtmosphereInterceptor must be executed before the default set of AtmosphereInterceptor
         */
        AFTER_DEFAULT,
        /**
         * The AtmosphereInterceptor must be executed after the default set of AtmosphereInterceptor
         */
        BEFORE_DEFAULT,
        /**
         * The AtmosphereInterceptor must be executed at first, before any AtmosphereInterceptor.
         */
        FIRST_BEFORE_DEFAULT
    }

    static PRIORITY AFTER_DEFAULT = PRIORITY.AFTER_DEFAULT;
    static PRIORITY BEFORE_DEFAULT = PRIORITY.BEFORE_DEFAULT;
    static PRIORITY FIRST_BEFORE_DEFAULT = PRIORITY.FIRST_BEFORE_DEFAULT;

    /**
     * Return the priority an AtmosphereInterceptor must be executed.
     * @return PRIORITY
     */
    PRIORITY priority();

}