/**
   * 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;
  }
 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);
   }
 }
  @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;
  }