@Override public AtmosphereResource suspend(long timeout) { if (event.isSuspended() || disableSuspend) return this; if (config.isSupportSession() && req.getSession(false) != null && req.getSession().getMaxInactiveInterval() != -1 && req.getSession().getMaxInactiveInterval() * 1000 < timeout) { throw new IllegalStateException( "Cannot suspend a " + "response longer than the session timeout. Increase the value of session-timeout in web.xml"); } if (transport().equals(TRANSPORT.JSONP) || transport().equals(TRANSPORT.LONG_POLLING)) { resumeOnBroadcast.set(true); } onPreSuspend(event); // Recheck based on preSuspend if (event.isSuspended() || disableSuspend) return this; if (!event.isResumedOnTimeout()) { Enumeration<String> connection = req.getHeaders("Connection"); if (connection == null) { connection = req.getHeaders("connection"); } if (connection != null && connection.hasMoreElements()) { String[] e = connection.nextElement().toString().split(","); for (String upgrade : e) { if (upgrade.trim().equalsIgnoreCase(WEBSOCKET_UPGRADE)) { if (!asyncSupport.supportWebSocket()) { response.addHeader(X_ATMOSPHERE_ERROR, "Websocket protocol not supported"); } else { req.setAttribute(FrameworkConfig.TRANSPORT_IN_USE, HeaderConfig.WEBSOCKET_TRANSPORT); } } } } if (req.getHeader(X_ATMOSPHERE_TRANSPORT) == null) { req.setAttribute(FrameworkConfig.TRANSPORT_IN_USE, HeaderConfig.LONG_POLLING_TRANSPORT); } req.setAttribute(PRE_SUSPEND, "true"); action.type(Action.TYPE.SUSPEND); action.timeout(timeout); // TODO: We can possibly optimize that call by avoiding creating a Broadcaster if we are sure // the Broadcaster // is unique. boolean isJersey = req.getAttribute(FrameworkConfig.CONTAINER_RESPONSE) != null; boolean skipCreation = false; if (req.getAttribute(SKIP_BROADCASTER_CREATION) != null) { skipCreation = true; } // Null means SCOPE=REQUEST set by a Meteor if (!skipCreation && (broadcaster == null || broadcaster.getScope() == Broadcaster.SCOPE.REQUEST) && !isJersey) { String id = broadcaster != null ? broadcaster.getID() : getClass().getName(); Class<? extends Broadcaster> clazz = broadcaster != null ? broadcaster.getClass() : DefaultBroadcaster.class; broadcaster = config.getBroadcasterFactory().lookup(clazz, id, false); if (broadcaster == null || broadcaster.getAtmosphereResources().size() > 0) { broadcaster = config.getBroadcasterFactory().lookup(clazz, id + "/" + UUID.randomUUID(), true); } } broadcaster.addAtmosphereResource(this); if (req.getAttribute(DefaultBroadcaster.CACHED) != null && transport() != null && (transport().equals(TRANSPORT.LONG_POLLING) || transport().equals(TRANSPORT.JSONP))) { action.type(Action.TYPE.CONTINUE); // Do nothing because we have found cached message which was written already, and the // handler resumed. logger.debug("Cached message found, not suspending {}", uuid()); return this; } req.removeAttribute(PRE_SUSPEND); notifyListeners(); } return this; }
/** * Invoke the {@link AtmosphereHandler#onRequest} method. * * @param req the {@link AtmosphereRequest} * @param res the {@link AtmosphereResponse} * @return action the Action operation. * @throws java.io.IOException * @throws javax.servlet.ServletException */ Action action(AtmosphereRequest req, AtmosphereResponse res) throws IOException, ServletException { boolean webSocketEnabled = false; if (req.getHeaders("Connection") != null && req.getHeaders("Connection").hasMoreElements()) { String[] e = req.getHeaders("Connection").nextElement().toString().split(","); for (String upgrade : e) { if (upgrade.equalsIgnoreCase("Upgrade")) { webSocketEnabled = true; break; } } } if (webSocketEnabled && !supportWebSocket()) { res.setStatus(501); res.addHeader(X_ATMOSPHERE_ERROR, "Websocket protocol not supported"); res.flushBuffer(); return new Action(); } if (config.handlers().isEmpty()) { logger.error( "No AtmosphereHandler found. Make sure you define it inside META-INF/atmosphere.xml"); throw new AtmosphereMappingException( "No AtmosphereHandler found. Make sure you define it insides META-INF/atmosphere.xml"); } if (supportSession()) { // Create the session needed to support the Resume // operation from disparate requests. HttpSession session = req.getSession(true); // Do not allow times out. if (session.getMaxInactiveInterval() == DEFAULT_SESSION_TIMEOUT) { session.setMaxInactiveInterval(-1); } } req.setAttribute(FrameworkConfig.SUPPORT_SESSION, supportSession()); AtmosphereHandlerWrapper handlerWrapper = map(req); // Check Broadcaster state. If destroyed, replace it. Broadcaster b = handlerWrapper.broadcaster; if (b.isDestroyed()) { synchronized (handlerWrapper) { config.getBroadcasterFactory().remove(b, b.getID()); handlerWrapper.broadcaster = config.getBroadcasterFactory().get(b.getID()); } } AtmosphereResourceImpl resource = new AtmosphereResourceImpl( config, handlerWrapper.broadcaster, req, res, this, handlerWrapper.atmosphereHandler); req.setAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE, resource); req.setAttribute(FrameworkConfig.ATMOSPHERE_HANDLER, handlerWrapper.atmosphereHandler); try { handlerWrapper.atmosphereHandler.onRequest(resource); } catch (IOException t) { resource.onThrowable(t); throw t; } if (trackActiveRequest && resource.getAtmosphereResourceEvent().isSuspended() && req.getAttribute(FrameworkConfig.CANCEL_SUSPEND_OPERATION) == null) { req.setAttribute(MAX_INACTIVE, System.currentTimeMillis()); aliveRequests.put(req, resource); } return resource.action(); }