All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.atmosphere.cpr.DefaultAsyncSupportResolver Maven / Gradle / Ivy

There is a newer version: 3.0.10
Show newest version
/*
 * Copyright 2015 Async-IO.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.atmosphere.cpr;

import org.atmosphere.container.BlockingIOCometSupport;
import org.atmosphere.container.GlassFishServ30WebSocketSupport;
import org.atmosphere.container.GlassFishWebSocketSupport;
import org.atmosphere.container.GlassFishv2CometSupport;
import org.atmosphere.container.Grizzly2CometSupport;
import org.atmosphere.container.Grizzly2WebSocketSupport;
import org.atmosphere.container.GrizzlyCometSupport;
import org.atmosphere.container.GrizzlyServlet30WebSocketSupport;
import org.atmosphere.container.JBossAsyncSupportWithWebSocket;
import org.atmosphere.container.JBossWebCometSupport;
import org.atmosphere.container.JSR356AsyncSupport;
import org.atmosphere.container.Jetty7CometSupport;
import org.atmosphere.container.Jetty9AsyncSupportWithWebSocket;
import org.atmosphere.container.JettyAsyncSupportWithWebSocket;
import org.atmosphere.container.JettyCometSupport;
import org.atmosphere.container.JettyServlet30AsyncSupportWithWebSocket;
import org.atmosphere.container.NettyCometSupport;
import org.atmosphere.container.Servlet30CometSupport;
import org.atmosphere.container.Tomcat7AsyncSupportWithWebSocket;
import org.atmosphere.container.Tomcat7CometSupport;
import org.atmosphere.container.Tomcat7Servlet30SupportWithWebSocket;
import org.atmosphere.container.TomcatCometSupport;
import org.atmosphere.container.WebLogicServlet30WithWebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedList;
import java.util.List;

/**
 * This is the default implementation of @link {AsyncSupportResolver}.
 *
 * @author Viktor Klang
 */
public class DefaultAsyncSupportResolver implements AsyncSupportResolver {

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

    public final static String SERVLET_30 = "javax.servlet.AsyncListener";
    public final static String GLASSFISH_V2 = "com.sun.enterprise.web.PEWebContainer";
    public final static String TOMCAT_7 = "org.apache.catalina.comet.CometFilterChain";
    public final static String TOMCAT_WEBSOCKET = "org.apache.coyote.http11.upgrade.UpgradeInbound";
    public final static String TOMCAT = "org.apache.coyote.http11.Http11NioProcessor";
    public final static String JBOSS_5 = "org.jboss.";
    public final static String JETTY = "org.mortbay.util.ajax.Continuation";
    public final static String JETTY_7 = "org.eclipse.jetty.servlet.ServletContextHandler";
    public final static String JETTY_8 = "org.eclipse.jetty.continuation.Servlet3Continuation";
    public final static String JETTY_9 = "org.eclipse.jetty.websocket.api.WebSocketPolicy";
    public final static String GRIZZLY = "com.sun.grizzly.http.servlet.ServletAdapter";
    public final static String GRIZZLY2 = "org.glassfish.grizzly.http.servlet.ServletHandler";
    public final static String JBOSSWEB = "org.apache.catalina.connector.HttpEventImpl";
    public final static String GRIZZLY_WEBSOCKET = "com.sun.grizzly.websockets.WebSocketEngine";
    public final static String GRIZZLY2_WEBSOCKET = "org.glassfish.grizzly.websockets.WebSocketEngine";
    public final static String NETTY = "org.jboss.netty.channel.Channel";
    public final static String JBOSS_AS7_WEBSOCKET = "org.atmosphere.jboss.as.websockets.servlet.WebSocketServlet";
    public final static String JSR356_WEBSOCKET = "javax.websocket.Endpoint";
    public final static String WEBLOGIC_WEBSOCKET = "weblogic.websocket.annotation.WebSocket";
    public final static String HK2 = "org.glassfish.hk2.utilities.reflection.ReflectionHelper";

    private final AtmosphereConfig config;

    public DefaultAsyncSupportResolver(final AtmosphereConfig config) {
        this.config = config;
    }

    /**
     * Convenience method that tests if a class with the given FQN is present on the classpath.
     *
     * @param testClass
     * @return true if the class is present
     */
    protected boolean testClassExists(final String testClass) {
        try {
            return testClass != null && testClass.length() > 0 &&
                    Thread.currentThread().getContextClassLoader().loadClass(testClass) != null;
        } catch (ClassNotFoundException ex) {
            return false;
        } catch (NoClassDefFoundError ex) {
            return false;
            // JDK 7
        } catch (UnsupportedClassVersionError ex) {
            return false;
        }
    }

    /**
     * Returns a list of comet support by containers available on the classpath.
     *
     * @return
     */
    public List> detectContainersPresent() {
        return new LinkedList>() {
            {
                if (testClassExists(GLASSFISH_V2))
                    add(GlassFishv2CometSupport.class);

                if (testClassExists(JETTY_9))
                    add(Jetty7CometSupport.class);

                if (testClassExists(JETTY_8))
                    add(Jetty7CometSupport.class);

                if (testClassExists(JETTY_7))
                    add(Jetty7CometSupport.class);

                if (testClassExists(JETTY))
                    add(JettyCometSupport.class);

                if (testClassExists(JBOSSWEB))
                    add(JBossWebCometSupport.class);

                if (testClassExists(TOMCAT_7))
                    add(Tomcat7CometSupport.class);

                if (testClassExists(TOMCAT) || testClassExists(JBOSS_5))
                    add(TomcatCometSupport.class);

                if (testClassExists(GRIZZLY))
                    add(GrizzlyCometSupport.class);

                if (testClassExists(GRIZZLY2))
                    add(Grizzly2CometSupport.class);

                if (testClassExists(NETTY))
                    add(NettyCometSupport.class);
            }
        };
    }

    public List> detectWebSocketPresent(final boolean useNativeIfPossible, final boolean useServlet30Async) {

        return new LinkedList>() {
            {
                if (useServlet30Async && !useNativeIfPossible) {

                    if (testClassExists(TOMCAT_WEBSOCKET))
                        add(Tomcat7Servlet30SupportWithWebSocket.class);

                    if (testClassExists(JETTY_9))
                        add(Jetty9AsyncSupportWithWebSocket.class);

                    if (testClassExists(JETTY_8))
                        add(JettyServlet30AsyncSupportWithWebSocket.class);

                    if (testClassExists(GRIZZLY2_WEBSOCKET))
                        add(GlassFishServ30WebSocketSupport.class);

                    if (testClassExists(GRIZZLY_WEBSOCKET))
                        add(GrizzlyServlet30WebSocketSupport.class);

                    if (testClassExists(WEBLOGIC_WEBSOCKET) && !testClassExists(HK2)) {
                        logger.warn("***************************************************************************************************");
                        logger.warn("WebLogic WebSocket detected and will be deployed under the hardcoded path <>/ws/*");
                        logger.warn("***************************************************************************************************");
                        add(WebLogicServlet30WithWebSocket.class);
                    }

                    if (testClassExists(JSR356_WEBSOCKET))
                        add(JSR356AsyncSupport.class);
                } else {
                    if (testClassExists(TOMCAT_WEBSOCKET))
                        add(Tomcat7AsyncSupportWithWebSocket.class);

                    if (testClassExists(JETTY_9))
                        add(Jetty9AsyncSupportWithWebSocket.class);

                    if (testClassExists(JETTY_8))
                        add(JettyAsyncSupportWithWebSocket.class);

                    if (testClassExists(GRIZZLY_WEBSOCKET))
                        add(GlassFishWebSocketSupport.class);

                    if (testClassExists(GRIZZLY2_WEBSOCKET))
                        add(Grizzly2WebSocketSupport.class);

                    if (testClassExists(JBOSS_AS7_WEBSOCKET))
                        add(JBossAsyncSupportWithWebSocket.class);

                    if (isEmpty()) {
                        if (testClassExists(JSR356_WEBSOCKET))
                            add(JSR356AsyncSupport.class);
                    }
                }
            }
        };
    }

    /**
     * This method is used to determine the default AsyncSupport if all else fails.
     *
     * @param preferBlocking
     * @return
     */
    public AsyncSupport defaultCometSupport(final boolean preferBlocking) {
        if (!preferBlocking && testClassExists(SERVLET_30)) {
            return new Servlet30CometSupport(config);
        } else {
            return new BlockingIOCometSupport(config);
        }
    }

    /**
     * Given a Class of something that extends AsyncSupport, it tries to return an instance of that class.
     * 

* The class has to have a visible constructor with the signature (@link {AtmosphereConfig}). * * @param targetClass * @return an instance of the specified class */ public AsyncSupport newCometSupport(final Class targetClass) { try { return (AsyncSupport) targetClass.getDeclaredConstructor(new Class[]{AtmosphereConfig.class}) .newInstance(config); } catch (final Exception e) { logger.error("Failed to create comet support class: {}, error: {}", targetClass, e); logger.error("Switching to BlockingIO"); return new BlockingIOCometSupport(config); } } public AsyncSupport newCometSupport(final String targetClassFQN) { try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return (AsyncSupport) cl.loadClass(targetClassFQN) .getDeclaredConstructor(new Class[]{AtmosphereConfig.class}).newInstance(config); } catch (final Exception e) { logger.error("Failed to create comet support class: {}, error: {}", targetClassFQN, e); throw new IllegalArgumentException("Unable to create " + targetClassFQN, e); } } /** * This method is the general interface to the outside world. * * @param useNativeIfPossible - should the resolver try to use a native container comet support if present? * @param defaultToBlocking - should the resolver default to blocking IO comet support? * @return an instance of AsyncSupport */ public AsyncSupport resolve(final boolean useNativeIfPossible, final boolean defaultToBlocking) { final AsyncSupport servletAsyncSupport = defaultCometSupport(defaultToBlocking); final AsyncSupport nativeSupport; if (!defaultToBlocking && (useNativeIfPossible || servletAsyncSupport.getClass().getName().equals(BlockingIOCometSupport.class.getName()))) { nativeSupport = resolveNativeCometSupport(detectContainersPresent()); return nativeSupport == null ? servletAsyncSupport : nativeSupport; } return servletAsyncSupport; } @Override public AsyncSupport resolve(boolean useNativeIfPossible, boolean defaultToBlocking, boolean useServlet30Async) { AsyncSupport cs = null; // Validate the value for old Servlet Container. useServlet30Async = testClassExists(SERVLET_30); if (!defaultToBlocking) { List> l = detectWebSocketPresent(useNativeIfPossible, useServlet30Async); if (!l.isEmpty()) { cs = resolveWebSocket(l); } } if (cs == null) { AsyncSupport nativeSupport = resolveNativeCometSupport(detectContainersPresent()); return nativeSupport == null ? defaultCometSupport(defaultToBlocking) : nativeSupport; } else { return cs; } } public AsyncSupport resolveWebSocket(final java.util.List> available) { if (available == null || available.isEmpty()) return null; else return newCometSupport(available.get(0)); } /** * This method is called to determine which native comet support to the used. * * @param available * @return the result of @link {resolveMultipleNativeSupportConflict} if there are more than 1 item in the list of available ontainers */ protected AsyncSupport resolveNativeCometSupport(final java.util.List> available) { if (available == null || available.isEmpty()) return null; else if (available.size() == 1) return newCometSupport(available.get(0)); else return resolveMultipleNativeSupportConflict(available); } /** * This method is called if there are more than one potential native container in scope. * * @return a AsyncSupport instance */ protected AsyncSupport resolveMultipleNativeSupportConflict(final List> available) { final StringBuilder b = new StringBuilder("Found multiple containers, please specify which one to use: "); for (Class cs : available) { b.append((cs != null) ? cs.getCanonicalName() : "null").append(", "); } b.append(" until you do, Atmosphere will use:" + available.get(0)); logger.warn("{}", b.toString()); return newCometSupport(available.get(0)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy