brooklyn.management.internal.SubscriptionTracker Maven / Gradle / Ivy
package brooklyn.management.internal;
import java.util.Collection;
import brooklyn.entity.Entity;
import brooklyn.entity.Group;
import brooklyn.event.Sensor;
import brooklyn.event.SensorEventListener;
import brooklyn.management.SubscriptionContext;
import brooklyn.management.SubscriptionHandle;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.SetMultimap;
/**
* Tracks subscriptions associated that are registered with particular entities. Gives utilities for unsubscribing from all
* subscriptions on a given entity, etc.
*/
public class SubscriptionTracker {
// This class is thread-safe. All modifications to subscriptions are synchronized on the
// "subscriptions" field. However, calls to alien code (i.e. context.subscribe etc) is
// done without holding the lock.
//
// If two threads do subscribe() and unsubscribeAll() concurrently, then it's non-derministic
// whether the subscription will be in place at the end (but that's unavoidable). However, it
// is guaranteed that the internal state of the SubscriptionTracker will be consistent: if
// the "subscriptions" includes the new subscription then that subscription will really exist,
// and vice versa.
protected SubscriptionContext context;
private final SetMultimap subscriptions = HashMultimap.create();
public SubscriptionTracker(SubscriptionContext subscriptionContext) {
this.context = subscriptionContext;
}
/** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
public SubscriptionHandle subscribe(Entity producer, Sensor sensor, SensorEventListener super T> listener) {
SubscriptionHandle handle = context.subscribe(producer, sensor, listener);
synchronized (subscriptions) {
subscriptions.put(producer, handle);
}
return handle;
}
/** @see SubscriptionContext#subscribeToChildren(Entity, Sensor, SensorEventListener) */
public SubscriptionHandle subscribeToChildren(Entity parent, Sensor sensor, SensorEventListener super T> listener) {
SubscriptionHandle handle = context.subscribeToChildren(parent, sensor, listener);
synchronized (subscriptions) {
subscriptions.put(parent, handle);
}
return handle;
}
/**
* @see SubscriptionContext#subscribeToMembers(Group, Sensor, SensorEventListener)
*/
public SubscriptionHandle subscribeToMembers(Group parent, Sensor sensor, SensorEventListener super T> listener) {
SubscriptionHandle handle = context.subscribeToMembers(parent, sensor, listener);
synchronized (subscriptions) {
subscriptions.put(parent, handle);
}
return handle;
}
/**
* Unsubscribes the given producer.
*
* @see SubscriptionContext#unsubscribe(SubscriptionHandle)
*/
public boolean unsubscribe(Entity producer) {
Collection handles;
synchronized (subscriptions) {
handles = subscriptions.removeAll(producer);
}
if (handles != null) {
for (SubscriptionHandle handle : handles) {
context.unsubscribe(handle);
}
return true;
}
return false;
}
/**
* Unsubscribes the given producer.
*
* @see SubscriptionContext#unsubscribe(SubscriptionHandle)
*/
public boolean unsubscribe(Entity producer, SubscriptionHandle handle) {
synchronized (subscriptions) {
subscriptions.remove(producer, handle);
}
return context.unsubscribe(handle);
}
/**
* @return an ordered list of all subscription handles
*/
public Collection getAllSubscriptions() {
synchronized (subscriptions) {
return ImmutableList.copyOf(subscriptions.values());
}
}
public void unsubscribeAll() {
Collection subscriptionsSnapshot;
synchronized (subscriptions) {
subscriptionsSnapshot = ImmutableList.copyOf(subscriptions.values());
subscriptions.clear();
}
for (SubscriptionHandle s: subscriptionsSnapshot) {
context.unsubscribe(s);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy