/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.brooklyn.core.mgmt.internal;
import static org.apache.brooklyn.util.JavaGroovyEquivalents.mapOf;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.Group;
import org.apache.brooklyn.api.mgmt.SubscriptionContext;
import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
import org.apache.brooklyn.api.mgmt.SubscriptionManager;
import org.apache.brooklyn.api.sensor.Sensor;
import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import groovy.lang.Closure;
/**
* A {@link SubscriptionContext} for an entity or other user of a {@link SubscriptionManager}.
*/
public class BasicSubscriptionContext implements SubscriptionContext {
private static final Logger LOG = LoggerFactory.getLogger(BasicSubscriptionContext.class);
private final SubscriptionManager manager;
private final Object subscriber;
private final Map<String,Object> flags;
public BasicSubscriptionContext(SubscriptionManager manager, Object subscriber) {
this(Collections.<String,Object>emptyMap(), manager, subscriber);
}
public BasicSubscriptionContext(Map<String, ?> flags, SubscriptionManager manager, Object subscriber) {
this.manager = manager;
this.subscriber = subscriber;
this.flags = mapOf("subscriber", subscriber);
if (flags!=null) this.flags.putAll(flags);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, Closure c) {
return subscribe(Collections.<String,Object>emptyMap(), producer, sensor, c);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribe(Map<String, ?> newFlags, Entity producer, Sensor<T> sensor, Closure c) {
return subscribe(newFlags, producer, sensor, toSensorEventListener(c));
}
@Override
public <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
return subscribe(Collections.<String,Object>emptyMap(), producer, sensor, listener);
}
@Override
public <T> SubscriptionHandle subscribe(Map<String, ?> newFlags, Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
Map<String,Object> subscriptionFlags = Maps.newLinkedHashMap(flags);
if (newFlags != null) subscriptionFlags.putAll(newFlags);
return manager.subscribe(subscriptionFlags, producer, sensor, listener);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribeToChildren(Entity parent, Sensor<T> sensor, Closure c) {
return subscribeToChildren(Collections.<String,Object>emptyMap(), parent, sensor, c);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribeToChildren(Map<String, Object> newFlags, Entity parent, Sensor<T> sensor, Closure c) {
return subscribeToChildren(newFlags, parent, sensor, toSensorEventListener(c));
}
@Override
public <T> SubscriptionHandle subscribeToChildren(Entity parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
return subscribeToChildren(Collections.<String,Object>emptyMap(), parent, sensor, listener);
}
@Override
public <T> SubscriptionHandle subscribeToChildren(Map<String, Object> newFlags, Entity parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
Map<String,Object> subscriptionFlags = Maps.newLinkedHashMap(flags);
if (newFlags != null) subscriptionFlags.putAll(newFlags);
return manager.subscribeToChildren(subscriptionFlags, parent, sensor, listener);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribeToMembers(Group parent, Sensor<T> sensor, Closure c) {
return subscribeToMembers(Collections.<String,Object>emptyMap(), parent, sensor, c);
}
@SuppressWarnings("rawtypes")
public <T> SubscriptionHandle subscribeToMembers(Map<String, Object> newFlags, Group parent, Sensor<T> sensor, Closure c) {
return subscribeToMembers(newFlags, parent, sensor, toSensorEventListener(c));
}
@Override
public <T> SubscriptionHandle subscribeToMembers(Group parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
return subscribeToMembers(Collections.<String,Object>emptyMap(), parent, sensor, listener);
}
@Override
public <T> SubscriptionHandle subscribeToMembers(Map<String, Object> newFlags, Group parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
Map<String,Object> subscriptionFlags = Maps.newLinkedHashMap(flags);
if (newFlags != null) subscriptionFlags.putAll(newFlags);
return manager.subscribeToMembers(subscriptionFlags, parent, sensor, listener);
}
@SuppressWarnings("rawtypes")
@Override
public boolean unsubscribe(SubscriptionHandle subscriptionId) {
Preconditions.checkNotNull(subscriptionId, "subscriptionId must not be null");
Preconditions.checkArgument(Objects.equal(subscriber, ((Subscription) subscriptionId).subscriber), "The subscriptionId is for a different "+subscriber+"; expected "+((Subscription) subscriptionId).subscriber);
return manager.unsubscribe(subscriptionId);
}
/** @see SubscriptionManager#publish(SensorEvent) */
@Override
public <T> void publish(SensorEvent<T> event) {
manager.publish(event);
}
/** Return the subscriptions associated with this context */
@Override
public Set<SubscriptionHandle> getSubscriptions() {
return manager.getSubscriptionsForSubscriber(subscriber);
}
@Override
public int unsubscribeAll() {
int count = 0;
// To avoid ConcurrentModificationException when copying subscriptions, need to synchronize on it
Set<SubscriptionHandle> subscriptions = getSubscriptions();
Collection<SubscriptionHandle> subscriptionsCopy;
synchronized (subscriptions) {
subscriptionsCopy = ImmutableList.copyOf(subscriptions);
}
for (SubscriptionHandle s : subscriptionsCopy) {
count++;
boolean result = unsubscribe(s);
if (!result) LOG.warn("When unsubscribing from all of {}, unsubscribe of {} return false", subscriber, s);
}
return count;
}
@SuppressWarnings("rawtypes")
private <T> SensorEventListener<T> toSensorEventListener(final Closure c) {
return new SensorEventListener<T>() {
@Override public void onEvent(SensorEvent<T> event) {
c.call(event);
}
};
}
}