protected Object perRequestFilter(AtmosphereResource<?, ?> r, Entry msg) { Object finalMsg = msg.message; if (AtmosphereResourceImpl.class.isAssignableFrom(r.getClass())) { if (AtmosphereResourceImpl.class.cast(r).isInScope()) { if (r.getRequest() instanceof HttpServletRequest && bc.hasPerRequestFilters()) { Object message = msg.originalMessage; BroadcastAction a = bc.filter( (HttpServletRequest) r.getRequest(), (HttpServletResponse) r.getResponse(), message); if (a.action() == BroadcastAction.ACTION.ABORT || a.message() != msg.originalMessage) { finalMsg = a.message(); } } trackBroadcastMessage(r, finalMsg); } else { // The resource is no longer valid. removeAtmosphereResource(r); BroadcasterFactory.getDefault().removeAllAtmosphereResource(r); } } return finalMsg; }
/** {@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; }
protected void start() { if (!started.getAndSet(true)) { broadcasterCache = bc.getBroadcasterCache(); broadcasterCache.start(); notifierFuture = bc.getExecutorService().submit(getBroadcastHandler()); asyncWriteFuture = bc.getAsyncWriteService().submit(getAsyncWriteHandler()); } }
/** {@inheritDoc} */ @Override public void setBroadcasterLifeCyclePolicy(final BroadcasterLifeCyclePolicy lifeCyclePolicy) { this.lifeCyclePolicy = lifeCyclePolicy; if (currentLifecycleTask != null) { currentLifecycleTask.cancel(false); } if (lifeCyclePolicy.getLifeCyclePolicy() == BroadcasterLifeCyclePolicy.ATMOSPHERE_RESOURCE_POLICY.IDLE || lifeCyclePolicy.getLifeCyclePolicy() == BroadcasterLifeCyclePolicy.ATMOSPHERE_RESOURCE_POLICY.IDLE_DESTROY) { int time = lifeCyclePolicy.getTimeout(); if (time == -1) { throw new IllegalStateException("BroadcasterLifeCyclePolicy time is not set"); } final AtomicReference<Future<?>> ref = new AtomicReference<Future<?>>(); currentLifecycleTask = bc.getScheduledExecutorService() .scheduleAtFixedRate( new Runnable() { @Override public void run() { try { if (resources.isEmpty()) { notifyEmptyListener(); notifyIdleListener(); if (lifeCyclePolicy.getLifeCyclePolicy() == BroadcasterLifeCyclePolicy.ATMOSPHERE_RESOURCE_POLICY.IDLE) { releaseExternalResources(); logger.debug("Applying BroadcasterLifeCyclePolicy IDLE policy"); } else { notifyDestroyListener(); destroy(); /** * The value may be null if the timeout is too low. Hopefully next * execution will cancel the task properly. */ if (ref.get() != null) { currentLifecycleTask.cancel(true); } logger.debug("Applying BroadcasterLifeCyclePolicy IDLE_DESTROY policy"); } } } catch (Throwable t) { logger.warn("Scheduled BroadcasterLifeCyclePolicy exception", t); } } }, time, time, lifeCyclePolicy.getTimeUnit()); ref.set(currentLifecycleTask); } }
/** {@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); } }
/** {@inheritDoc} */ public void destroy() { started.set(false); destroyed.set(true); releaseExternalResources(); if (notifierFuture != null) { notifierFuture.cancel(true); } if (asyncWriteFuture != null) { asyncWriteFuture.cancel(true); } if (bc != null) { bc.destroy(); } if (broadcasterCache != null) { broadcasterCache.stop(); } resources.clear(); broadcastOnResume.clear(); messages.clear(); asyncWriteQueue.clear(); delayedBroadcast.clear(); broadcasterCache = null; if (BroadcasterFactory.getDefault() != null) { BroadcasterFactory.getDefault().remove(this, name); } if (currentLifecycleTask != null) { currentLifecycleTask.cancel(true); } }
/** {@inheritDoc} */ public <T> Future<T> delayBroadcast(final T o, long delay, TimeUnit t) { if (destroyed.get()) throw new IllegalStateException("This Broadcaster has been destroyed and cannot be used"); start(); final Object msg = filter(o); if (msg == null) return null; final BroadcasterFuture<Object> future = new BroadcasterFuture<Object>(msg); final Entry e = new Entry(msg, null, future, o); Future<T> f; if (delay > 0) { f = bc.getScheduledExecutorService() .schedule( new Callable<T>() { public T call() throws Exception { delayedBroadcast.remove(e); if (Callable.class.isAssignableFrom(o.getClass())) { try { Object r = Callable.class.cast(o).call(); final Object msg = filter(r); if (msg != null) { Entry entry = new Entry(msg, null, null, r); push(entry); } return (T) msg; } catch (Exception e1) { logger.error("", e); } } final Object msg = filter(o); final Entry e = new Entry(msg, null, null, o); push(e); return (T) msg; } }, delay, t); e.future = new BroadcasterFuture<Object>(f, msg); } delayedBroadcast.offer(e); return future; }
protected void onException(Throwable t, final AtmosphereResource<?, ?> r) { logger.debug("onException()", t); if (r instanceof AtmosphereEventLifecycle) { ((AtmosphereEventLifecycle) r) .notifyListeners( new AtmosphereResourceEventImpl((AtmosphereResourceImpl) r, true, false, t)); ((AtmosphereEventLifecycle) r).removeEventListeners(); } /** Make sure we resume the connection on every IOException. */ bc.getAsyncWriteService() .execute( new Runnable() { @Override public void run() { r.resume(); } }); }
/** {@inheritDoc} */ public Future<?> scheduleFixedBroadcast(final Object o, long waitFor, long period, TimeUnit t) { if (destroyed.get()) throw new IllegalStateException("This Broadcaster has been destroyed and cannot be used"); start(); if (period == 0 || t == null) { return null; } final Object msg = filter(o); if (msg == null) return null; return bc.getScheduledExecutorService() .scheduleWithFixedDelay( new Runnable() { public void run() { if (Callable.class.isAssignableFrom(o.getClass())) { try { Object r = Callable.class.cast(o).call(); final Object msg = filter(r); if (msg != null) { Entry entry = new Entry(msg, null, null, r); push(entry); } return; } catch (Exception e) { logger.error("", e); } } final Object msg = filter(o); final Entry e = new Entry(msg, null, null, o); push(e); } }, waitFor, period, t); }
/** * Invoke the {@link BroadcastFilter} * * @param msg * @return */ protected Object filter(Object msg) { BroadcastAction a = bc.filter(msg); if (a.action() == BroadcastAction.ACTION.ABORT || msg == null) return null; else return a.message(); }