package org.yamcs.yarch; import java.util.Collection; import java.util.Collections; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.yamcs.utils.LoggingUtils; public abstract class AbstractStream implements Stream { protected String name; protected TupleDefinition outputDefinition; final protected Collection<StreamSubscriber> subscribers=new ConcurrentLinkedQueue<StreamSubscriber>(); protected volatile int state=SETUP; protected Logger log; protected YarchDatabase ydb; private volatile AtomicLong emitedTuples=new AtomicLong(); private volatile AtomicInteger subscriberCount=new AtomicInteger(); protected AbstractStream(YarchDatabase ydb, String name, TupleDefinition definition) { this.name = name; this.outputDefinition = definition; this.ydb = ydb; log = LoggingUtils.getLogger(this.getClass(), ydb.getName(), this); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#start() */ @Override public abstract void start() ; /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getDefinition() */ @Override public TupleDefinition getDefinition() { return outputDefinition; } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#emitTuple(org.yamcs.yarch.Tuple) */ @Override public void emitTuple(Tuple t) { emitedTuples.incrementAndGet(); for(StreamSubscriber s:subscribers) { try { s.onTuple(this,t); } catch(Exception e) { log.warn("Exception received when emitting tuple to subscriber "+s+": {}", e); throw e; } } } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getName() */ @Override public String getName() { return name; } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#setName(java.lang.String) */ @Override public void setName(String streamName) { this.name=streamName; } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#addSubscriber(org.yamcs.yarch.StreamSubscriber) */ @Override public void addSubscriber(StreamSubscriber s) { subscribers.add(s); subscriberCount.incrementAndGet(); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#removeSubscriber(org.yamcs.yarch.StreamSubscriber) */ @Override public void removeSubscriber(StreamSubscriber s) { subscribers.remove(s); subscriberCount.decrementAndGet(); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getColumnDefinition(java.lang.String) */ @Override public ColumnDefinition getColumnDefinition(String colName) { return outputDefinition.getColumn(colName); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#close() */ @Override final public void close() { if(state==QUITTING)return; state=QUITTING; ydb.removeStream(name); log.debug("Closed stream {} num emitted tuples: {}", name, getNumEmittedTuples()); doClose(); for(StreamSubscriber s:subscribers) { s.streamClosed(this); } } protected abstract void doClose(); @Override public String toString() { return name; } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getState() */ @Override public int getState() { return state; } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getNumEmittedTuples() */ @Override public long getNumEmittedTuples() { return emitedTuples.get(); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getSubscriberCount() */ @Override public int getSubscriberCount() { return subscriberCount.get(); } /* (non-Javadoc) * @see org.yamcs.yarch.Stream#getSubscribers() */ @Override public Collection<StreamSubscriber> getSubscribers() { return Collections.unmodifiableCollection(subscribers); } }