void invokeAtmosphereHandler(AtmosphereResourceImpl r) throws IOException {
    if (!r.isInScope()) return;

    AtmosphereRequest req = r.getRequest(false);
    String disableOnEvent =
        r.getAtmosphereConfig().getInitParameter(ApplicationConfig.DISABLE_ONSTATE_EVENT);

    try {
      if (disableOnEvent == null || !disableOnEvent.equals(String.valueOf(true))) {
        AtmosphereHandler atmosphereHandler =
            (AtmosphereHandler) req.getAttribute(FrameworkConfig.ATMOSPHERE_HANDLER);

        synchronized (r) {
          atmosphereHandler.onStateChange(r.getAtmosphereResourceEvent());

          Meteor m = (Meteor) req.getAttribute(AtmosphereResourceImpl.METEOR);
          if (m != null) {
            m.destroy();
          }
        }
        req.removeAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE);
      }
    } catch (IOException ex) {
      try {
        r.onThrowable(ex);
      } catch (Throwable t) {
        logger.warn("failed calling onThrowable()", ex);
      }
    }
  }
  @Override
  public AtmosphereResource notifyListeners(AtmosphereResourceEvent event) {
    if (listeners.size() > 0) {
      logger.trace("Invoking listener with {}", event);
    } else {
      return this;
    }

    Action oldAction = action;
    try {
      if (event.isClosedByApplication()) {
        onClose(event);
      } else if (event.isCancelled() || event.isClosedByClient()) {
        if (!disconnected.getAndSet(true)) {
          onDisconnect(event);
        }
      } else if (event.isResuming() || event.isResumedOnTimeout()) {
        onResume(event);
      } else if (!isSuspendEvent.getAndSet(true) && event.isSuspended()) {
        onSuspend(event);
      } else if (event.throwable() != null) {
        onThrowable(event);
      } else {
        onBroadcast(event);
      }

      if (oldAction.type() != action.type()) {
        action().type(Action.TYPE.CREATED);
      }
    } catch (Throwable t) {
      logger.debug("Listener error {}", t);
      AtmosphereResourceEventImpl.class.cast(event).setThrowable(t);
      try {
        onThrowable(event);
      } catch (Throwable t2) {
        logger.warn("Listener error {}", t2);
      }
    }
    return this;
  }
 /**
  * Notify {@link AtmosphereResourceEventListener} thah an unexpected exception occured.
  *
  * @pram a {@link Throwable}
  */
 public void onThrowable(Throwable t) {
   onThrowable(new AtmosphereResourceEventImpl(this, false, false, t));
 }
  /**
   * 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();
  }