public <T> void publish(final SensorEvent<T> event) {
    // REVIEW 1459 - execution

    // delivery in parallel/background, using execution manager

    // subscriptions, should define SingleThreadedScheduler for any subscriber ID tag
    // in order to ensure callbacks are invoked in the order they are submitted
    // (recommend exactly one per subscription to prevent deadlock)
    // this is done with:
    // em.setTaskSchedulerForTag(subscriberId, SingleThreadedScheduler.class);

    // note, generating the notifications must be done in the calling thread to preserve order
    // e.g. emit(A); emit(B); should cause onEvent(A); onEvent(B) in that order
    if (LOG.isTraceEnabled()) LOG.trace("{} got a {} event", this, event);
    totalEventsPublishedCount.incrementAndGet();

    Set<Subscription> subs =
        (Set<Subscription>)
            ((Set<?>) getSubscriptionsForEntitySensor(event.getSource(), event.getSensor()));
    if (groovyTruth(subs)) {
      if (LOG.isTraceEnabled())
        LOG.trace(
            "sending {}, {} to {}",
            new Object[] {event.getSensor().getName(), event, join(subs, ",")});
      for (Subscription s : subs) {
        if (s.eventFilter != null && !s.eventFilter.apply(event)) continue;
        final Subscription sAtClosureCreation = s;
        em.submit(
            mapOf("tag", s.subscriberExecutionManagerTag),
            new Runnable() {
              public void run() {
                sAtClosureCreation.listener.onEvent(event);
              }
            });
        totalEventsDeliveredCount.incrementAndGet();
      }
    }
  }
 static Object makeEntitySensorToken(SensorEvent<?> se) {
   return makeEntitySensorToken(se.getSource(), se.getSensor());
 }