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