Understanding BroadcastFilter

Sebastian Lövdahl edited this page Aug 8, 2013 · 7 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

To begin, make sure you have read the Understanding Broadcaster document before reading this one.

BroadcastFilter and PerRequestBroadcastFilter are useful for transforming, accumulating or discarding broadcasted messages. BroadcastFilter is defined as:

    /**
     * Transform or Filter a message. Return BroadcastAction(ACTION.ABORT, message)
     * {@link Broadcaster} to discard the message, e.g to not broadcast it.
     *
     * @param originalMessage The original message which was {@link Broadcaster#broadcast(Object)};
     * @param message         Object a message
     * @return a transformed message.
     */
    BroadcastAction filter(Object originalMessage, Object message);

When invoking Broadcaster#broadcast, all BroadcastFilters are applied, giving an application a chance to play with the message before it gets delivered to the browser. The list of BroadcastFilter objects is always invoked first, followed by PerRequestBroadcastFilter objects. A BroadcastAction is used to tell the framework, whether or not to deliver a message to the browser. As an example, the following BroadcastFilter accumulates String objects, until the resulting String is large enough, reducing the number of write operations:

public class StringFilterAggregator implements BroadcastFilter {

    private final int maxBufferedString;

    private final AtomicReference<StringBuilder> bufferedMessage = new AtomicReference<StringBuilder>(new StringBuilder());

    public StringFilterAggregator() {
        maxBufferedString = 256;
    }

    public StringFilterAggregator(int maxBufferedString) {
        this.maxBufferedString = maxBufferedString;
    }

    public BroadcastAction filter(Object originalMessage, Object message) {
        if (message instanceof String) {
            bufferedMessage.get().append(message);
            if (bufferedMessage.get().length() < maxBufferedString) {
                return new BroadcastAction(ACTION.ABORT, message);
            } else {
                message = bufferedMessage.toString();
                bufferedMessage.get().delete(0, bufferedMessage.get().length());
                return new BroadcastAction(ACTION.CONTINUE, message);
            }
        } else {
            return new BroadcastAction(message);
        }
    }
}

Until the maxBufferedString size is reached, messages will be buffered. BroadcastAction is defined as:

    public class BroadcastAction {

        private final ACTION a;
        private final Object o;
        private Object originalMsg;

        public enum ACTION {
            CONTINUE, ABORT
        }

        public BroadcastAction(ACTION a, Object o) {
            this.a = a;
            this.o = o;
        }

        public BroadcastAction(Object o) {
            this.a = ACTION.CONTINUE;
            this.o = o;
        }

        public Object message() {
            return o;
        }

        public ACTION action() {
            return a;
        }

        public Object originalMessage() {
            return originalMsg;
        }

        void setOriginalMsg(Object originalMsg) {
            this.originalMsg = originalMsg;
        }
    }

The PerRequestBroadcastFilter extends BroadcastFilter by allowing to manipulate the AtmosphereResource associated with the browser. This is useful when you need to customize a message based on some headers, browsers (like user-agent), etc. The API is defined as:

public interface PerRequestBroadcastFilter extends BroadcastFilter {

    /**
     * Transform or Filter a message per request, with V as an indicator. Be careful when setting headers on the
     * {@link AtmosphereResponse} as the headers may have been already sent back to the browser.
     *
     *
     * @param atmosphereResource
     * @param message  Object a message
     * @param originalMessage The original message that was broadcasted.
     * @return a transformed message.
     */
    BroadcastAction filter(AtmosphereResource atmosphereResource, Object originalMessage, Object message);
}

As an example, the following PerRequestBroadcastFilter customizes the message using the JSONP technique:

public class JSONPTransportFilter implements PerRequestBroadcastFilter {
    @Override
    public BroadcastAction filter(HttpServletRequest request, HttpServletResponse response, Object message) {

        String s = request.getParameter(HeaderConfig.JSONP_CALLBACK_NAME);
        if (s != null) {
            String jsonPMessage = s + "({"message" :  + message})";
            return new BroadcastAction(jsonPMessage);
        }

        return new BroadcastAction(message);
    }

    @Override
    public BroadcastAction filter(Object originalMessage, Object message) {
        return new BroadcastAction(message);
    }
}

BroadcastFilter and PerRequestBroadcastFilter can be added programmatically using the following:

   Broadcaster b = BroadcasterFactory.getDefault()....;
   b.getBroadcastConfig().addFilter(new BroadcastFilter());

or using web.xml

        <init-param>
            <param-name>org.atmosphere.cpr.broadcastFilterClasses</param-name>
            <param-value>//coma separated list of BroadcastFilter</param-value>
        </init-param>

or in atmosphere.xml

        <applicationConfig>
            <param-name>org.atmosphere.cpr.broadcastFilterClasses</param-name>
            <param-value>//coma separated list of BroadcastFilter</param-value>
        </applicationConfig>

When defined in web/atmosphere.xml, the list of BroadcastFilter are added to all new instance of Broadcaster.