/** {@inheritDoc} */
  public synchronized void destroy() {

    String s = config.getInitParameter(ApplicationConfig.SHARED);
    if (s != null && s.equalsIgnoreCase("true")) {
      logger.warn(
          "Factory shared, will not be destroyed. That can possibly cause memory leaks if"
              + "Broadcaster where created. Make sure you destroy them manually.");
      return;
    }

    Enumeration<Broadcaster> e = store.elements();
    Broadcaster b;
    // We just need one when shared.
    BroadcasterConfig bc = null;
    while (e.hasMoreElements()) {
      try {
        b = e.nextElement();
        b.resumeAll();
        b.destroy();
        bc = b.getBroadcasterConfig();
      } catch (Throwable t) {
        // Shield us from any bad behaviour
        logger.trace("Destroy", t);
      }
    }

    try {
      if (bc != null) bc.forceDestroy();
    } catch (Throwable t) {
      logger.trace("Destroy", t);
    }

    store.clear();
    factory = null;
  }
  private Broadcaster createBroadcaster(Class<? extends Broadcaster> c, Object id)
      throws BroadcasterCreationException {
    try {
      Broadcaster b =
          c.getConstructor(String.class, AtmosphereConfig.class).newInstance(id.toString(), config);
      InjectorProvider.getInjector().inject(b);

      if (b.getBroadcasterConfig() == null) {
        b.setBroadcasterConfig(
            new BroadcasterConfig(config.framework().broadcasterFilters, config));
      }

      b.setBroadcasterLifeCyclePolicy(policy);
      if (DefaultBroadcaster.class.isAssignableFrom(clazz)) {
        DefaultBroadcaster.class.cast(b).start();
      }

      for (BroadcasterListener l : broadcasterListeners) {
        b.addBroadcasterListener(l);
      }
      notifyOnPostCreate(b);
      return b;
    } catch (Throwable t) {
      throw new BroadcasterCreationException(t);
    }
  }
Пример #3
0
  /**
   * Create a {@link Meteor} using the {@link HttpServletRequest} and use a list of {@link
   * BroadcastFilter} and {@link Serializer} for writing the result of a broadcast operation the
   * {@link HttpServletResponse}.
   *
   * @param req an {@link HttpServletRequest}
   * @param scope the {@link Broadcaster.SCOPE}}
   * @param l a list of {@link BroadcastFilter}
   * @param s a {@link Serializer} used when writing broadcast events
   * @return a {@link Meteor} than can be used to resume, suspend and broadcast {@link Object}
   */
  public static final Meteor build(
      HttpServletRequest req, Broadcaster.SCOPE scope, List<BroadcastFilter> l, Serializer s) {
    AtmosphereResource r = (AtmosphereResource) req.getAttribute(ATMOSPHERE_RESOURCE);
    if (r == null) throw new IllegalStateException("MeteorServlet not defined in web.xml");

    Broadcaster b = null;
    if (scope == Broadcaster.SCOPE.REQUEST) {
      try {
        BroadcasterFactory f = r.getAtmosphereConfig().getBroadcasterFactory();
        b =
            f.get(
                DefaultBroadcaster.class,
                DefaultBroadcaster.class.getSimpleName()
                    + r.getAtmosphereConfig().uuidProvider().generateUuid());
      } catch (Throwable t) {
        throw new RuntimeException(t);
      }
      b.setScope(scope);
      r.setBroadcaster(b);
      req.setAttribute(AtmosphereResourceImpl.SKIP_BROADCASTER_CREATION, Boolean.TRUE);
    }

    Meteor m = new Meteor(r, l, (s != null ? s : r.getSerializer()));
    req.setAttribute(METEOR, m);
    return m;
  }
Пример #4
0
  /** {@inheritDoc} */
  public void setScope(SCOPE scope) {
    this.scope = scope;
    if (scope != SCOPE.REQUEST) {
      return;
    }

    try {
      for (AtmosphereResource<?, ?> resource : resources) {
        Broadcaster b =
            BroadcasterFactory.getDefault()
                .get(getClass(), getClass().getSimpleName() + "/" + UUID.randomUUID());

        if (DefaultBroadcaster.class.isAssignableFrom(this.getClass())) {
          BroadcasterCache cache = bc.getBroadcasterCache().getClass().newInstance();
          InjectorProvider.getInjector().inject(cache);
          DefaultBroadcaster.class.cast(b).broadcasterCache = cache;
        }
        resource.setBroadcaster(b);
        if (resource.getAtmosphereResourceEvent().isSuspended()) {
          b.addAtmosphereResource(resource);
        }
      }

      if (!resources.isEmpty()) {
        destroy();
      }
    } catch (Exception e) {
      logger.error("failed to set request scope for current resources", e);
    }
  }
 @Override
 public String toString() {
   try {
     return "AtmosphereResource{"
         + "\n\t uuid="
         + uuid
         + ",\n\t transport="
         + transport()
         + ",\n\t isInScope="
         + isInScope
         + ",\n\t isResumed="
         + isResumed()
         + ",\n\t isCancelled="
         + isCancelled()
         + ",\n\t isSuspended="
         + isSuspended()
         + ",\n\t broadcaster="
         + broadcaster.getID()
         + " size: "
         + broadcaster.getAtmosphereResources().size()
         + ",\n\t atmosphereHandler="
         + atmosphereHandler
         + ",\n\t action="
         + action
         + '}';
   } catch (NullPointerException ex) {
     // Prevent logger
     return "AtmosphereResourceImpl{" + uuid + "}";
   }
 }
Пример #6
0
  /** Sends leave message to everyone ARRG knows :) */
  public void broadcastLeave() {
    VirtualSocketAddress[] addresses = arrg.getRandomMembers(nrOfLeavesSend);

    Broadcaster broadcaster = new Broadcaster(this, addresses);

    // wait for all the broadcasts to be finished
    broadcaster.waitUntilDone();
  }
Пример #7
0
  /** {@inheritDoc} */
  public void setID(String id) {
    if (id == null) {
      id = getClass().getSimpleName() + "/" + UUID.randomUUID();
    }

    Broadcaster b = BroadcasterFactory.getDefault().lookup(this.getClass(), id);
    if (b != null && b.getScope() == SCOPE.REQUEST) {
      throw new IllegalStateException(
          "Broadcaster ID already assigned to SCOPE.REQUEST. Cannot change the id");
    }

    BroadcasterFactory.getDefault().remove(this, name);
    this.name = id;
    BroadcasterFactory.getDefault().add(this, name);
  }
  @Test
  public void testEmptyDestroy() throws IOException, ServletException {
    Broadcaster b = framework.getBroadcasterFactory().lookup(B.class, "/test", true);
    b.setBroadcasterLifeCyclePolicy(BroadcasterLifeCyclePolicy.EMPTY_DESTROY);
    AR ah = new AR();

    framework.addAtmosphereHandler("/*", ah, b).init();
    AtmosphereRequest request =
        new AtmosphereRequestImpl.Builder().pathInfo("/a").method("GET").build();
    framework.doCometSupport(request, AtmosphereResponseImpl.newInstance());
    b.removeAtmosphereResource(ah.resource);

    assertFalse(B.class.cast(b).releaseExternalResources.get());
    assertTrue(B.class.cast(b).destroy.get());
  }
  public synchronized void cancel() throws IOException {
    action.type(Action.TYPE.RESUME);
    if (isCancelled.getAndSet(true)) return;

    if (asyncSupport instanceof AsynchronousProcessor) {
      try {
        AsynchronousProcessor.class.cast(asyncSupport).resumed(req, response);
      } catch (ServletException e) {
        logger.trace("", e);
      }
    }
    asyncSupport.action(this);
    // We must close the underlying WebSocket as well.
    if (AtmosphereResponse.class.isAssignableFrom(response.getClass())) {
      AtmosphereResponse.class.cast(response).close();
      AtmosphereResponse.class.cast(response).destroy();
    }

    if (AtmosphereRequest.class.isAssignableFrom(req.getClass())) {
      AtmosphereRequest.class.cast(req).destroy();
    }

    // TODO: Grab some measurement.
    //        req = null;
    //        response = null;

    // Just in case
    if (broadcaster != null) {
      broadcaster.removeAtmosphereResource(this);
    }
    event.destroy();
  }
  @Test
  public void findTest() {
    Broadcaster b1 = BroadcasterFactory.getDefault().get("b1");
    Broadcaster b2 = BroadcasterFactory.getDefault().get("b2");
    AtmosphereResource r =
        AtmosphereResourceFactory.getDefault()
            .create(
                mock(AtmosphereConfig.class),
                b1,
                AtmosphereResponse.newInstance().request(AtmosphereRequest.create()),
                mock(AsyncSupport.class),
                mock(AtmosphereHandler.class));
    assertNotNull(r);

    b2.addAtmosphereResource(r);

    assertNotNull(AtmosphereResourceFactory.getDefault().find(r.uuid()));
  }
 /** {@inheritDoc} */
 @Override
 public void removeAllAtmosphereResource(AtmosphereResource r) {
   // Remove inside all Broadcaster as well.
   try {
     if (store.size() > 0) {
       for (Broadcaster b : lookupAll()) {
         try {
           // Prevent deadlock
           if (b.getAtmosphereResources().contains(r)) {
             b.removeAtmosphereResource(r);
           }
         } catch (IllegalStateException ex) {
           logger.trace(ex.getMessage(), ex);
         }
       }
     }
   } catch (Exception ex) {
     logger.warn(ex.getMessage(), ex);
   }
 }
  @Test
  public void deleteTest() {
    for (int i = 0; i < 10; i++) {
      BroadcasterFactory.getDefault().get(String.valueOf(i));
    }
    Broadcaster b2 = BroadcasterFactory.getDefault().get("b2");
    AtmosphereResource r =
        AtmosphereResourceFactory.getDefault()
            .create(
                mock(AtmosphereConfig.class),
                BroadcasterFactory.getDefault().lookup("1"),
                AtmosphereResponse.newInstance().request(AtmosphereRequest.create()),
                mock(AsyncSupport.class),
                mock(AtmosphereHandler.class));
    assertNotNull(r);
    b2.addAtmosphereResource(r);

    assertNotNull(AtmosphereResourceFactory.getDefault().find(r.uuid()));
    assertEquals(AtmosphereResourceFactory.getDefault().remove(r.uuid()), r);
    assertNull(AtmosphereResourceFactory.getDefault().find(r.uuid()));
  }
  /** {@inheritDoc} */
  @Override
  public Broadcaster lookup(Class<? extends Broadcaster> c, Object id, boolean createIfNull) {
    Broadcaster b = store.get(id);
    if (b != null && !c.isAssignableFrom(b.getClass())) {
      String msg =
          "Invalid lookup class " + c.getName() + ". Cached class is: " + b.getClass().getName();
      logger.debug(msg);
      throw new IllegalStateException(msg);
    }

    if ((b == null && createIfNull) || (b != null && b.isDestroyed())) {
      if (b != null) {
        logger.debug("Removing destroyed Broadcaster {}", b.getID());
        store.remove(b.getID(), b);
      }

      Broadcaster nb = store.get(id);
      if (nb == null) {
        nb = createBroadcaster(c, id);
        store.put(id, nb);
      }

      if (nb == null) {
        logger.debug("Added Broadcaster {} . Factory size: {}", id, store.size());
      }

      b = nb;
    }

    return b;
  }
  protected Broadcaster getBroadcaster(boolean autoCreate) {
    if (broadcaster == null) {
      throw new IllegalStateException("No Broadcaster associated with this AtmosphereResource.");
    }

    String s = config.getInitParameter(ApplicationConfig.RECOVER_DEAD_BROADCASTER);
    if (s != null) {
      autoCreate = Boolean.parseBoolean(s);
    }

    if (autoCreate && broadcaster.isDestroyed() && config.getBroadcasterFactory() != null) {
      logger.debug(
          "Broadcaster {} has been destroyed and cannot be re-used. Recreating a new one with the same name. You can turn off this"
              + " mechanism by adding, in web.xml, {} set to false",
          broadcaster.getID(),
          ApplicationConfig.RECOVER_DEAD_BROADCASTER);

      Broadcaster.SCOPE scope = broadcaster.getScope();
      synchronized (this) {
        String id =
            scope != Broadcaster.SCOPE.REQUEST
                ? broadcaster.getID()
                : broadcaster.getID() + ".recovered" + UUID.randomUUID();

        // Another Thread may have added the Broadcaster.
        broadcaster = config.getBroadcasterFactory().lookup(id, true);
        broadcaster.setScope(scope);
        broadcaster.addAtmosphereResource(this);
      }
    }
    return broadcaster;
  }
  @BeforeMethod
  public void setUp() throws Exception {
    AtmosphereConfig config = new AtmosphereFramework().getAtmosphereConfig();
    DefaultBroadcasterFactory factory =
        new DefaultBroadcasterFactory(ExcludeSessionBroadcaster.class, "NEVER", config);
    broadcaster = factory.get(ExcludeSessionBroadcaster.class, "test");
    atmosphereHandler = new AR();
    ar =
        new AtmosphereResourceImpl(
            config,
            broadcaster,
            mock(AtmosphereRequest.class),
            AtmosphereResponse.create(),
            mock(BlockingIOCometSupport.class),
            atmosphereHandler);

    broadcaster.addAtmosphereResource(ar);
  }
Пример #16
0
  public void cancel() throws IOException {

    if (!isCancelled.getAndSet(true)) {
      logger.trace("Cancelling {}", uuid);
      action.type(Action.TYPE.RESUME);
      asyncSupport.action(this);
      // We must close the underlying WebSocket as well.
      if (AtmosphereResponse.class.isAssignableFrom(response.getClass())) {
        AtmosphereResponse.class.cast(response).close();
        AtmosphereResponse.class.cast(response).destroy();
      }

      if (AtmosphereRequest.class.isAssignableFrom(req.getClass())) {
        AtmosphereRequest.class.cast(req).destroy();
      }

      if (broadcaster != null) {
        broadcaster.removeAtmosphereResource(this);
      }
      event.destroy();
    }
  }
 @Override
 public String toString() {
   return "AtmosphereResourceImpl{"
       + "\n uuid="
       + uuid
       + ",\n transport="
       + transport()
       + ",\n action="
       + action
       + ",\n isResumed="
       + isResumed()
       + ",\n isCancelled="
       + isCancelled()
       + ",\n isSuspended="
       + isSuspended()
       + ",\n broadcaster="
       + broadcaster.getID()
       + ",\n isInScope="
       + isInScope
       + ",\n listeners="
       + listeners
       + '}';
 }
  @Override
  public AtmosphereResource resume() {

    if (!isSuspended()) {
      logger.warn("AtmosphereResource {} not suspend, cannot resume it.", uuid());
      return this;
    }

    try {
      if (!isResumed.getAndSet(true) && isInScope.get()) {
        logger.trace("AtmosphereResource {} is resuming", uuid());

        action.type(Action.TYPE.RESUME);

        // We need it as Jetty doesn't support timeout
        Broadcaster b = getBroadcaster(false);
        if (!b.isDestroyed() && b instanceof DefaultBroadcaster) {
          ((DefaultBroadcaster) b).broadcastOnResume(this);
        }

        notifyListeners();

        try {
          if (!b.isDestroyed()) {
            broadcaster.removeAtmosphereResource(this);
          }
        } catch (IllegalStateException ex) {
          logger.warn("Unable to resume", this);
          logger.debug(ex.getMessage(), ex);
        }

        if (b.getScope() == Broadcaster.SCOPE.REQUEST) {
          logger.debug("Broadcaster's scope is set to request, destroying it {}", b.getID());
          b.destroy();
        }

        // Resuming here means we need to pull away from all other Broadcaster, if they exists.
        if (config.getBroadcasterFactory() != null) {
          config.getBroadcasterFactory().removeAllAtmosphereResource(this);
        }

        try {
          req.setAttribute(ApplicationConfig.RESUMED_ON_TIMEOUT, Boolean.FALSE);
        } catch (Exception ex) {
          logger.debug("Resume exception: Cannot resume an already resumed/cancelled request", ex);
        } finally {
          try {
            Meteor m = (Meteor) req.getAttribute(METEOR);
            if (m != null) {
              m.destroy();
            }
          } catch (Exception ex) {
            logger.debug(
                "Meteor resume exception: Cannot resume an already resumed/cancelled request", ex);
          }
        }

        if (req.getAttribute(PRE_SUSPEND) == null) {
          asyncSupport.action(this);
        }
      } else {
        logger.trace("Already resumed {}", this);
        return this;
      }
    } catch (Throwable t) {
      logger.trace("Wasn't able to resume a connection {}", this, t);
    }
    listeners.clear();
    return this;
  }
Пример #19
0
  public void saveImage(byte[] img) {
    try {
      Image image = new Image(img);
      System.out.println(
          "SenderName: "
              + image.senderName
              + " Filename: "
              + image.filename
              + " Message: "
              + image.message
              + " Location: "
              + image.location);

      if (image.senderName.equals(TabActivity.senderName)) {
        return;
      }

      // checking image is exist in database?
      mCursor =
          sqLiteDatabase.rawQuery(
              "SELECT * FROM "
                  + MyDatabase.TABLE_NAME_PICTURE
                  + " WHERE "
                  + MyDatabase.COL_SENDER_NAME
                  + " = '"
                  + image.senderName
                  + "' AND "
                  + MyDatabase.COL_FILE_NAME
                  + " = '"
                  + image.filename
                  + "' AND "
                  + MyDatabase.COL_MESSAGE
                  + " = '"
                  + image.message
                  + "' AND "
                  + MyDatabase.COL_LOCATION
                  + " = '"
                  + image.location
                  + "'",
              null);

      if (mCursor.getCount() == 0) {
        if (image.imageBytes != null) {
          String filename = image.filename.substring(0, image.filename.length() - 4);
          File file = ManageImage.setUpPhotoFile(mAlbumStorageDirFactory, filename);
          System.out.println("filename :====" + file.getName());
          FileOutputStream fileOutputStream = new FileOutputStream(file);
          fileOutputStream.write(image.getImageBytes());
          ManageImage.galleryAddPic(file.getAbsolutePath(), activity);
        }
        myDatabase.addToTablePicture(
            sqLiteDatabase, image.senderName, image.filename, image.message, image.location);

        Log.d(TAG, "Finished...");

        LogFragment.print(
            "Time recieve: "
                + getCurrentTimeStamp()
                + " | From: "
                + image.senderName
                + " | Message:  "
                + image.message);

        //                LogFragment.print("Time recieve: " + System.currentTimeMillis() + " |
        // From: " + image.senderName + " | Message:  " + image.message);

        System.out.println("TestRecieveData: " + System.currentTimeMillis());

        final String sentMsg = "Received";
        activity.runOnUiThread(
            new Runnable() {
              @Override
              public void run() {
                NewFeedFragment.updateTable();
                Toast.makeText(activity, sentMsg, Toast.LENGTH_LONG).show();
              }
            });

        // Sent to other node
        if (getIPAddressItSelf().equals("0.0.0.0")) {
          Broadcaster.broadcast(image.getBytes(), ListenerPacket.PORT_PACKET);
        }
      }
      ;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (ImageChunkIncorrectLengthException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  /** {@inheritDoc} */
  @Override
  public synchronized AtmosphereResource resume() {
    // We need to synchronize the method because the resume may occurs at the same time a message is
    // published
    // and we will miss that message. The DefaultBroadcaster synchronize on that method before
    // writing a message.
    try {
      if (!isResumed && isInScope) {
        action.type(Action.TYPE.RESUME);
        isResumed = true;

        // We need it as Jetty doesn't support timeout
        Broadcaster b = getBroadcaster(false);
        if (!b.isDestroyed() && b instanceof DefaultBroadcaster) {
          ((DefaultBroadcaster) b).broadcastOnResume(this);
        }

        notifyListeners();

        try {
          if (!b.isDestroyed()) {
            broadcaster.removeAtmosphereResource(this);
          }
        } catch (IllegalStateException ex) {
          logger.warn("Unable to resume", this);
          logger.debug(ex.getMessage(), ex);
        }

        if (b.getScope() == Broadcaster.SCOPE.REQUEST) {
          logger.debug("Broadcaster's scope is set to request, destroying it {}", b.getID());
          b.destroy();
        }

        // Resuming here means we need to pull away from all other Broadcaster, if they exists.
        if (config.getBroadcasterFactory() != null) {
          config.getBroadcasterFactory().removeAllAtmosphereResource(this);
        }

        try {
          req.setAttribute(ApplicationConfig.RESUMED_ON_TIMEOUT, Boolean.FALSE);
        } catch (Exception ex) {
          logger.debug("Resume exception: Cannot resume an already resumed/cancelled request", ex);
        } finally {
          try {
            Meteor m = (Meteor) req.getAttribute(METEOR);
            if (m != null) {
              m.destroy();
            }
          } catch (Exception ex) {
            logger.debug(
                "Meteor resume exception: Cannot resume an already resumed/cancelled request", ex);
          }
        }

        if (req.getAttribute(PRE_SUSPEND) == null) {
          asyncSupport.action(this);
        }
      } else {
        logger.debug("Cannot resume an already resumed/cancelled request {}", this);
      }
    } catch (Throwable t) {
      logger.trace("Wasn't able to resume a connection {}", this, t);
    }
    notifyListeners(new AtmosphereResourceEventImpl(this, true, false));
    listeners.clear();
    return this;
  }
 protected final void syncRemote(K key, Broadcaster.EVENT syncAction) {
   Broadcaster.getInstance().queue(syncType.getType(), syncAction.getType(), key.toString());
 }
 @AfterMethod
 public void unSetUp() throws Exception {
   broadcaster.removeAtmosphereResource(ar);
   atmosphereHandler.value.set(new HashSet());
 }
 @Test
 public void testDirectBroadcastMethod()
     throws ExecutionException, InterruptedException, ServletException {
   broadcaster.broadcast("foo", ar).get();
   assertEquals(atmosphereHandler.value.get(), new HashSet());
 }
  @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();
  }