package org.epics.archiverappliance.retrieval.workers;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import org.apache.log4j.Logger;
import org.epics.archiverappliance.Event;
import org.epics.archiverappliance.EventStream;
import org.epics.archiverappliance.retrieval.RemotableEventStreamDesc;
import org.epics.archiverappliance.retrieval.RemotableOverRaw;
/**
* Expands the results from a Reader using the current thread.
* This is the default strategy for most retrievals; especially if the data sizes are large; here, we leverage streaming to minimize memory consumption.
* We only support one iterator for this stream.
* @author mshankar
*
*/
public class CurrentThreadWorkerEventStream implements EventStream, RemotableOverRaw {
private static Logger logger = Logger.getLogger(CurrentThreadWorkerEventStream.class.getName());
private String pvName;
private List<Callable<EventStream>> theStreams = null;
private CurrentThreadWorkerEventStreamIterator theIterator = null;
public CurrentThreadWorkerEventStream(String pvName, List<Callable<EventStream>> streams) {
this.pvName = pvName;
this.theStreams = streams;
theIterator = new CurrentThreadWorkerEventStreamIterator();
}
@Override
public void close() throws IOException {
if(theIterator != null) {
theIterator.close();
theIterator = null;
}
}
@Override
public Iterator<Event> iterator() {
// We only support one iterator out of this stream.
return theIterator;
}
@Override
public RemotableEventStreamDesc getDescription() {
return ((RemotableOverRaw)theIterator.currStream).getDescription();
}
private class CurrentThreadWorkerEventStreamIterator implements Iterator<Event>, AutoCloseable {
private Event nextEvent = null;
private int currentStreamIndex = 0;
private EventStream currStream = null;
private Iterator<Event> currStreamIterator = null;
public CurrentThreadWorkerEventStreamIterator() {
try {
if(theStreams != null && theStreams.size() > 0) {
currStream = theStreams.get(currentStreamIndex).call();
currStreamIterator = currStream.iterator();
}
} catch(Exception ex) {
logger.error("Exception fetching events from stream for pv " + pvName, ex);
}
}
@Override
public boolean hasNext() {
if(currStream == null || currStreamIterator == null) return false;
nextEvent = fetchNextEvent();
return (nextEvent != null);
}
@Override
public Event next() {
return nextEvent;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void close() throws IOException {
nextEvent = null;
if(currStream != null) currStream.close();
currStream = null;
currStreamIterator = null;
}
private Event fetchNextEvent() {
try {
for(int infiniteloopprevention = 0; infiniteloopprevention < theStreams.size(); infiniteloopprevention++) {
if(currStreamIterator.hasNext()) {
return currStreamIterator.next();
}
if(currStream != null) {
currStream.close();
currStream = null;
}
currStreamIterator = null;
currentStreamIndex++;
if(currentStreamIndex >= theStreams.size()) {
return null;
}
currStream = theStreams.get(currentStreamIndex).call();
currStreamIterator = currStream.iterator();
}
} catch(Exception ex) {
logger.error("Exception fetching events from stream for pv " + pvName, ex);
}
return null;
}
}
}