/** {@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); } }
/** * 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; }
/** {@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 + "}"; } }
/** 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(); }
/** {@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); }
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; }
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(); }