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 void action(AtmosphereResourceImpl r) {
   super.action(r);
   if (r.action().type() == Action.TYPE.RESUME && r.isInScope()) {
     HttpEvent event = (HttpEvent) r.getRequest(false).getAttribute(HTTP_EVENT);
     if (event != null && !r.transport().equals(AtmosphereResource.TRANSPORT.WEBSOCKET)) {
       close(event);
     }
   }
 }
 public void timedOut() {
   try {
     ((AsynchronousProcessor) r.cometSupport)
         .timedout(r.getRequest(false), r.getResponse(false));
   } catch (IOException e) {
     logger.debug("", e);
   } catch (ServletException e) {
     logger.debug("", e);
   }
 }
 public void closed() {
   try {
     ((AsynchronousProcessor) r.cometSupport)
         .cancelled(r.getRequest(false), r.getResponse(false));
   } catch (IOException e) {
     logger.debug("", e);
   } catch (ServletException e) {
     logger.debug("", e);
   }
 }
 /** {@inheritDoc} */
 @Override
 public void action(AtmosphereResourceImpl r) {
   super.action(r);
   if (r.isResumed() && r.getRequest().getAttribute(ASYNCHRONOUS_HOOK) != null) {
     if (r.getRequest().getAttribute(CHANNEL) == null) return;
     try {
       ((AsyncIOWriter) r.getRequest().getAttribute(CHANNEL)).close();
     } catch (IOException e) {
       logger.trace("", e);
     }
   }
 }
  /** {@inheritDoc} */
  @Override
  public void action(AtmosphereResourceImpl resource) {
    super.action(resource);
    if (resource.action().type() == Action.TYPE.RESUME && resource.isInScope()) {
      try {
        CometEvent event = (CometEvent) resource.getRequest().getAttribute(COMET_EVENT);
        if (event == null) return;

        // Resume without closing the underlying suspended connection.
        if (config.getInitParameter(ApplicationConfig.RESUME_AND_KEEPALIVE) == null
            || config
                .getInitParameter(ApplicationConfig.RESUME_AND_KEEPALIVE)
                .equalsIgnoreCase("false")) {
          bz51881(event);
        }
      } catch (IOException ex) {
        logger.debug("action failed", ex);
      }
    }
  }
  /**
   * All proprietary Comet based {@link Servlet} must invoke the cancelled method when the
   * underlying WebServer detect that the client closed the connection.
   *
   * @param req the {@link AtmosphereRequest}
   * @param res the {@link AtmosphereResponse}
   * @return action the Action operation.
   * @throws java.io.IOException
   * @throws javax.servlet.ServletException
   */
  public Action cancelled(AtmosphereRequest req, AtmosphereResponse res)
      throws IOException, ServletException {

    synchronized (req) {
      AtmosphereResourceImpl r = null;
      try {
        if (trackActiveRequest) {
          long l = (Long) req.getAttribute(MAX_INACTIVE);
          if (l == -1) {
            // The closedDetector closed the connection.
            return timedoutAction;
          }
          req.setAttribute(MAX_INACTIVE, (long) -1);
        }

        logger.debug("Cancelling the connection for request {}", req);

        r = (AtmosphereResourceImpl) req.getAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE);
        if (r != null) {
          r.getAtmosphereResourceEvent().setCancelled(true);
          invokeAtmosphereHandler(r);

          try {
            r.getResponse().sendError(503);
            r.getResponse().getOutputStream().close();
          } catch (Throwable t) {
            try {
              r.getResponse().getWriter().close();
            } catch (Throwable t2) {
            }
          }
        }
      } catch (Throwable ex) {
        // Something wrong happenned, ignore the exception
        logger.debug("failed to cancel resource: " + r, ex);
      } finally {
        try {
          if (r != null) {
            r.notifyListeners();
            r.setIsInScope(false);
            r.cancel();
          }
        } catch (Throwable t) {
          logger.trace("cancel", t);
        } finally {
          if (r != null) {
            destroyResource(r);
          }
        }
      }
    }

    return cancelledAction;
  }
 @Override
 public AsyncSupport complete(AtmosphereResourceImpl r) {
   final HttpEvent event = (HttpEvent) r.getRequest(false).getAttribute(HTTP_EVENT);
   // Prevent Deadlock
   // https://github.com/Atmosphere/atmosphere/issues/1782
   if (event != null) {
     if (!r.isResumed()) {
       ExecutorsFactory.getScheduler(config)
           .schedule(
               new Runnable() {
                 @Override
                 public void run() {
                   close(event);
                 }
               },
               500,
               TimeUnit.MILLISECONDS);
     } else {
       close(event);
     }
   }
   return this;
 }
  /** {@inheritDoc} */
  @Override
  public void action(AtmosphereResourceImpl r) {
    try {
      super.action(r);
      if (r.action().type() == Action.TYPE.RESUME) {
        AtmosphereRequest req = r.getRequest(false);
        CountDownLatch latch = null;

        if (req.getAttribute(LATCH) != null) {
          latch = (CountDownLatch) req.getAttribute(LATCH);
        }

        String s = config.getInitParameter(ApplicationConfig.RESUME_AND_KEEPALIVE);
        if (latch != null && (s == null || s.equalsIgnoreCase("false"))) {
          latch.countDown();
        } else if (req.getAttribute(AtmosphereResourceImpl.PRE_SUSPEND) == null) {
          logger.trace("Unable to resume the suspended connection");
        }
      }
    } catch (Exception ex) {
      logger.error("", ex);
    }
  }
  @Override
  public Action inspect(final AtmosphereResource ar) {
    final AtmosphereResourceImpl r = AtmosphereResourceImpl.class.cast(ar);
    final AtmosphereRequest request = r.getRequest(false);
    final AtmosphereResponse response = r.getResponse(false);

    String uuid = request.getHeader(HeaderConfig.X_ATMOSPHERE_TRACKING_ID);
    String handshakeUUID = request.getHeader(HeaderConfig.X_ATMO_PROTOCOL);
    if (uuid != null && uuid.equals("0") && handshakeUUID != null) {
      request.header(HeaderConfig.X_ATMO_PROTOCOL, null);
      // Since 1.0.10

      final StringBuffer message =
          new StringBuffer(r.uuid()).append(wsDelimiter).append(System.currentTimeMillis());

      // https://github.com/Atmosphere/atmosphere/issues/993
      boolean track = false;
      if (r.getBroadcaster().getBroadcasterConfig().hasFilters()) {
        for (BroadcastFilter bf : r.getBroadcaster().getBroadcasterConfig().filters()) {
          if (TrackMessageSizeFilter.class.isAssignableFrom(bf.getClass())) {
            track = true;
            break;
          }
        }
      }

      final AtomicReference<String> protocolMessage =
          new AtomicReference<String>(message.toString());
      if (track) {
        protocolMessage.set(
            (String) f.filter(r, protocolMessage.get(), protocolMessage.get()).message());
      }

      if (!Utils.resumableTransport(r.transport())) {
        OnSuspend a =
            new OnSuspend() {
              @Override
              public void onSuspend(AtmosphereResourceEvent event) {
                response.write(protocolMessage.get());
                try {
                  response.flushBuffer();
                } catch (IOException e) {
                  logger.trace("", e);
                }
              }
            };
        // Pass the information to Servlet Based Framework
        request.setAttribute(CALLBACK_JAVASCRIPT_PROTOCOL, a);
        r.addEventListener(a);
      } else {
        response.write(protocolMessage.get());
      }

      // We don't need to reconnect here
      if (r.transport() == AtmosphereResource.TRANSPORT.WEBSOCKET
          || r.transport() == AtmosphereResource.TRANSPORT.STREAMING
          || r.transport() == AtmosphereResource.TRANSPORT.SSE) {
        return Action.CONTINUE;
      } else {
        return Action.SKIP_ATMOSPHEREHANDLER;
      }
    }
    return Action.CONTINUE;
  }
  /**
   * All proprietary Comet based {@link Servlet} must invoke the timedout method when the underlying
   * WebServer time out the {@link AtmosphereResponse}. The returned value, of type {@link Action},
   * tells the proprietary Comet {@link Servlet} to resume (again), suspended or do nothing with the
   * current {@link AtmosphereResponse}.
   *
   * @param request the {@link AtmosphereRequest}
   * @param response the {@link AtmosphereResponse}
   * @return action the Action operation.
   * @throws java.io.IOException
   * @throws javax.servlet.ServletException
   */
  public Action timedout(AtmosphereRequest request, AtmosphereResponse response)
      throws IOException, ServletException {

    AtmosphereResourceImpl r = null;
    try {
      if (trackActiveRequest) {
        long l = (Long) request.getAttribute(MAX_INACTIVE);
        if (l == -1) {
          // The closedDetector closed the connection.
          return timedoutAction;
        }
        request.setAttribute(MAX_INACTIVE, (long) -1);
      }

      logger.debug("Timing out the connection for request {}", request);

      // Something went wrong.
      if (request == null || response == null) {
        logger.warn("Invalid Request/Response: {}/{}", request, response);
        return timedoutAction;
      }

      r = (AtmosphereResourceImpl) request.getAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE);

      if (r != null && r.getAtmosphereResourceEvent().isSuspended()) {
        r.getAtmosphereResourceEvent().setIsResumedOnTimeout(true);

        Broadcaster b = r.getBroadcaster();
        if (b instanceof DefaultBroadcaster) {
          ((DefaultBroadcaster) b).broadcastOnResume(r);
        }

        if (request.getAttribute(ApplicationConfig.RESUMED_ON_TIMEOUT) != null) {
          r.getAtmosphereResourceEvent()
              .setIsResumedOnTimeout(
                  (Boolean) request.getAttribute(ApplicationConfig.RESUMED_ON_TIMEOUT));
        }

        invokeAtmosphereHandler(r);
      }
    } catch (Throwable t) {
      logger.error("failed to timeout resource {}", r, t);
    } finally {
      try {
        if (r != null) {
          r.notifyListeners();
          r.setIsInScope(false);
          r.cancel();
        }
      } catch (Throwable t) {
        logger.trace("timedout", t);
      } finally {

        try {
          response.getOutputStream().close();
        } catch (Throwable t) {
          try {
            response.getWriter().close();
          } catch (Throwable t2) {
          }
        }

        if (r != null) {
          destroyResource(r);
        }
      }
    }

    return timedoutAction;
  }
 /** {@inheritDoc} */
 public void action(AtmosphereResourceImpl r) {
   if (trackActiveRequest) {
     aliveRequests.remove(r.getRequest(false));
   }
 }
  /**
   * 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();
  }