org.jnap.core.mvc.async.AsyncResponseHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.jnap.core.mvc.async.AsyncResponseHandler.java

Source

/*
 * AsyncResponseHandler.java created on 2011-11-30
 *
 * Created by Brushing Bits Labs
 * http://www.brushingbits.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jnap.core.mvc.async;

import static org.atmosphere.cpr.HeaderConfig.LONG_POLLING_TRANSPORT;
import static org.atmosphere.cpr.HeaderConfig.WEBSOCKET_UPGRADE;
import static org.atmosphere.cpr.HeaderConfig.X_ATMOSPHERE_TRANSPORT;

import java.util.ArrayList;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.atmosphere.annotation.Suspend;
import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereEventLifecycle;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEventListener;
import org.atmosphere.cpr.BroadcastFilter;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.cpr.BroadcasterFactory;
import org.atmosphere.cpr.ClusterBroadcastFilter;
import org.atmosphere.cpr.FrameworkConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author Daniel Rochetti
 * @since 0.9.3
 */
public class AsyncResponseHandler {

    private static Logger logger = LoggerFactory.getLogger(AsyncResponseHandler.class);

    private final AsyncState state;
    private final long timeout;
    private final int waitFor;
    private final Suspend.SCOPE scope;
    private final boolean outputComments;
    private final Class<BroadcastFilter>[] filters;
    private final String topic;

    private AtmosphereResourceEventListener[] listeners = null;
    private final ArrayList<ClusterBroadcastFilter> clusters = new ArrayList<ClusterBroadcastFilter>();

    public AsyncResponseHandler(AsyncState state) {
        this(state, -1);
    }

    public AsyncResponseHandler(AsyncState state, long timeout) {
        this(state, timeout, 0);
    }

    public AsyncResponseHandler(AsyncState state, long timeout, int waitFor) {
        this(state, timeout, waitFor, Suspend.SCOPE.APPLICATION);
    }

    public AsyncResponseHandler(AsyncState state, long timeout, int waitFor, Suspend.SCOPE scope) {
        this(state, timeout, waitFor, scope, true);
    }

    public AsyncResponseHandler(AsyncState state, long timeout, int waitFor, Suspend.SCOPE scope,
            boolean outputComments) {
        this(state, timeout, waitFor, scope, outputComments, null, null);
    }

    public AsyncResponseHandler(AsyncState state, long timeout, int waitFor, Suspend.SCOPE scope,
            boolean outputComments, Class<BroadcastFilter>[] filters, String topic) {
        this.state = state;
        this.timeout = timeout;
        this.waitFor = waitFor;
        this.scope = scope;
        this.outputComments = outputComments;
        this.filters = filters;
        this.topic = topic;
    }

    /**
     * 
     * @param request
     * @param response
     * @param modelAndView
     */
    public void handle(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {

        AtmosphereResource<HttpServletRequest, HttpServletResponse> asyncResource = (AtmosphereResource<HttpServletRequest, HttpServletResponse>) request
                .getAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE);

        boolean sessionSupported = (Boolean) request.getAttribute(FrameworkConfig.SUPPORT_SESSION);

        AsyncResponseModel asyncResponseModel = AsyncResponseModel.class.isInstance(modelAndView)
                ? AsyncResponseModel.class.cast(modelAndView)
                : null;

        switch (state) {
        case SUSPEND_RESPONSE:
            Assert.notNull(asyncResponseModel); // TODO detailed message
            break;
        case SUBSCRIBE_TRACKABLE:
        case SUBSCRIBE:
        case SUSPEND_TRACKABLE:
        case SUSPEND:
        case SUSPEND_RESUME:

            boolean outputJunk = shouldOutputComments(request, outputComments);
            boolean resumeOnBroadcast = shouldResumeOnBroadcast(request, (state == AsyncState.SUSPEND_RESUME));
            bindEventListeners(asyncResource);

            Broadcaster broadcaster = null; // TODO (Broadcaster) servletReq.getAttribute(INJECTED_BROADCASTER);

            if (state == AsyncState.SUBSCRIBE) {
                broadcaster = resolveBroadcaster(request);
            }

            suspend(sessionSupported, resumeOnBroadcast, outputJunk, this.timeout, request, response, broadcaster,
                    asyncResource, this.scope);

            break;
        case RESUME:
            break;
        case BROADCAST:
        case PUBLISH:
        case RESUME_ON_BROADCAST:

            break;
        case SCHEDULE:
        case SCHEDULE_RESUME:
        default:
            throw new IllegalStateException("");
        }
    }

    /**
     * 
     * @param sessionSupported
     * @param resumeOnBroadcast
     * @param comments
     * @param timeout
     * @param request
     * @param response
     * @param broadcaster
     * @param resource
     * @param localScope
     */
    protected void suspend(boolean sessionSupported, boolean resumeOnBroadcast, boolean comments, long timeout,
            HttpServletRequest request, HttpServletResponse response, Broadcaster broadcaster,
            AtmosphereResource<HttpServletRequest, HttpServletResponse> resource, Suspend.SCOPE localScope) {

        BroadcasterFactory broadcasterFactory = (BroadcasterFactory) request
                .getAttribute(ApplicationConfig.BROADCASTER_FACTORY);

        resource.suspend(timeout, comments);
    }

    /**
     * @param asyncResource
     */
    protected void bindEventListeners(AtmosphereResource<HttpServletRequest, HttpServletResponse> asyncResource) {
        if (listeners != null && listeners.length > 0 && AtmosphereEventLifecycle.class.isInstance(asyncResource)) {
            AtmosphereEventLifecycle asyncEventLifecycle = AtmosphereEventLifecycle.class.cast(asyncResource);
            for (AtmosphereResourceEventListener listener : listeners) {
                asyncEventLifecycle.addEventListener(listener);
            }
        }
    }

    /**
     * 
     * @param request
     * @param shouldResume
     * @return
     */
    protected boolean shouldResumeOnBroadcast(HttpServletRequest request, boolean shouldResume) {
        String transport = request.getHeader(X_ATMOSPHERE_TRANSPORT);
        if (transport != null && transport.equals(LONG_POLLING_TRANSPORT)) {
            return true;
        }
        return shouldResume;
    }

    /**
     * 
     * @param request
     * @param output
     * @return
     */
    protected boolean shouldOutputComments(HttpServletRequest request, boolean output) {
        boolean webSocketEnabled = false;
        if (request.getHeaders("Connection") != null && request.getHeaders("Connection").hasMoreElements()) {
            String[] e = ((Enumeration<String>) request.getHeaders("Connection")).nextElement().split(",");
            for (String upgrade : e) {
                if (upgrade.trim().equalsIgnoreCase(WEBSOCKET_UPGRADE)) {
                    webSocketEnabled = true;
                    break;
                }
            }
        }

        String transport = request.getHeader(X_ATMOSPHERE_TRANSPORT);
        if (webSocketEnabled || (transport != null && transport.equals(LONG_POLLING_TRANSPORT))) {
            return false;
        }

        return output;
    }

    /**
     * @param request
     * @return 
     */
    protected Broadcaster resolveBroadcaster(HttpServletRequest request) {
        Class<Broadcaster> broadcasterType = null;
        try {
            broadcasterType = (Class<Broadcaster>) Class
                    .forName((String) request.getAttribute(ApplicationConfig.BROADCASTER_CLASS));
        } catch (Throwable e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        return BroadcasterFactory.getDefault().lookup(broadcasterType, topic, true);
    }

    public void setListeners(AtmosphereResourceEventListener[] listeners) {
        this.listeners = listeners;
    }

}