package org.yamcs.container;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.yamcs.ContainerExtractionResult;
import org.yamcs.Processor;
import org.yamcs.utils.LoggingUtils;
import org.yamcs.xtce.SequenceContainer;
import org.yamcs.xtce.XtceDb;
import org.yamcs.xtceproc.ContainerListener;
import org.yamcs.xtceproc.XtceTmProcessor;
/**
* Keeps track of the subscribers to the containers of a Yamcs Channel.
*/
public class ContainerRequestManager implements ContainerListener {
private Logger log;
// For each container, all the subscribers
private Map<SequenceContainer, Set<ContainerConsumer>> subscriptions = new ConcurrentHashMap<>();
private XtceTmProcessor tmProcessor;
/**
* Creates a new ContainerRequestManager, configured to listen to a newly
* created XtceTmProcessor.
*/
public ContainerRequestManager(Processor proc) {
this(proc, new XtceTmProcessor(proc, null));
}
/**
* Creates a new ContainerRequestManager, configured to listen to the
* specified XtceTmProcessor.
*/
public ContainerRequestManager(Processor proc, XtceTmProcessor tmProcessor) {
this.tmProcessor = tmProcessor;
log = LoggingUtils.getLogger(this.getClass(), proc);
tmProcessor.setContainerListener(this);
}
public synchronized void subscribe(ContainerConsumer subscriber, SequenceContainer container) {
if (container == null) {
throw new NullPointerException("Null contaienr");
}
addSubscription(subscriber, container);
}
public synchronized void subscribeAll(ContainerConsumer subscriber) {
for (SequenceContainer c : tmProcessor.xtcedb.getSequenceContainers()) {
addSubscription(subscriber, c);
}
}
private void addSubscription(ContainerConsumer subscriber, SequenceContainer container) {
if (!subscriptions.containsKey(container)) {
subscriptions.put(container, new HashSet<ContainerConsumer>());
tmProcessor.startProviding(container);
}
subscriptions.get(container).add(subscriber);
}
public synchronized void unsubscribe(ContainerConsumer subscriber, SequenceContainer container) {
if (container == null) {
throw new NullPointerException("null container");
}
if (subscriptions.containsKey(container)) {
Set<ContainerConsumer> subscribers = subscriptions.get(container);
if (subscribers.remove(subscriber)) {
if(subscribers.isEmpty()) {
// The following call does not do anything (yet)
tmProcessor.stopProviding(container);
}
} else {
log.warn("Container removal requested for {} but not subscribed", container);
}
} else {
log.warn("Container removal requested for {} but not subscribed", container);
}
}
public synchronized void unsubscribeAll(ContainerConsumer subscriber) {
for (Entry<SequenceContainer, Set<ContainerConsumer>> entry : subscriptions.entrySet()) {
Set<ContainerConsumer> subscribers = entry.getValue();
subscribers.remove(subscriber);
if (subscribers.isEmpty()) {
// The following call does not do anything (yet)
tmProcessor.stopProviding(entry.getKey());
}
}
}
@Override
public synchronized void update(List<ContainerExtractionResult> results) {
log.trace("Getting update of {} container(s)", results.size());
for (ContainerExtractionResult result : results) {
SequenceContainer def = result.getContainer();
if (!subscriptions.containsKey(def)) {
continue;
}
for (ContainerConsumer subscriber : subscriptions.get(def)) {
subscriber.processContainer(result);
}
}
}
public XtceTmProcessor getTmProcessor() {
return tmProcessor;
}
public XtceDb getXtceDb() {
return tmProcessor.getXtceDb();
}
}