package org.epics.archiverappliance.retrieval.postprocessors; import java.io.IOException; import java.sql.Timestamp; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Set; import org.apache.log4j.Logger; import org.epics.archiverappliance.Event; import org.epics.archiverappliance.EventStream; import org.epics.archiverappliance.common.POJOEvent; import org.epics.archiverappliance.common.TimeUtils; import org.epics.archiverappliance.data.AlarmInfo; import org.epics.archiverappliance.engine.membuf.ArrayListEventStream; import org.epics.archiverappliance.retrieval.ChangeInYearsException; import org.epics.archiverappliance.retrieval.RemotableEventStreamDesc; import org.epics.archiverappliance.retrieval.RemotableOverRaw; /** * This is similar to the summary stats collector except we keep aspects of the original event stream like dbr_type and so on. * * @author mshankar * @see PostProcessorWithConsolidatedEventStream */ public class FillsCollectorEventStream implements EventStream, RemotableOverRaw { private static Logger logger = Logger.getLogger(FillsCollectorEventStream.class.getName()); private final RemotableEventStreamDesc desc; private LinkedHashMap<Long, Event> consolidatedData; private long firstBin; private long lastBin; private int intervalSecs; private Iterator<Event> theOneAndOnlyIterator; private boolean fillOperator = true; public FillsCollectorEventStream(long firstBin, long lastBin, int intervalSecs, RemotableEventStreamDesc desc, LinkedHashMap<Long, Event> consolidatedData) { this.firstBin = firstBin; this.lastBin = lastBin; this.intervalSecs = intervalSecs; this.desc = new RemotableEventStreamDesc(desc); this.consolidatedData = consolidatedData; } public FillsCollectorEventStream(long firstBin, long lastBin, int intervalSecs, RemotableEventStreamDesc desc, LinkedHashMap<Long, Event> consolidatedData, boolean fillOperator) { this(firstBin,lastBin,intervalSecs,desc,consolidatedData); this.fillOperator = fillOperator; } @Override public void close() throws IOException { } @Override public Iterator<Event> iterator() { if(theOneAndOnlyIterator != null) { return theOneAndOnlyIterator; } else { theOneAndOnlyIterator = new FillsCollectorEventStreamIterator(); return theOneAndOnlyIterator; } } @Override public RemotableEventStreamDesc getDescription() { return desc; } private class FillsCollectorEventStreamIterator implements Iterator<Event> { ArrayListEventStream strm = new ArrayListEventStream(consolidatedData.size(), desc); short currentYear = -1; int currentEvent = 0; int totalEvents = -1; FillsCollectorEventStreamIterator() { Event currentEvent = null; if(consolidatedData.isEmpty()) { logger.info("We not seem to have any events"); totalEvents = 0; return; } Set<Long> bins = consolidatedData.keySet(); if(firstBin == 0) { firstBin = Collections.min(bins); } if(lastBin == Long.MAX_VALUE) { lastBin = Collections.max(bins); } for(long binNum = firstBin; binNum <= lastBin; binNum++) { if(consolidatedData.containsKey(binNum)) { currentEvent = consolidatedData.get(binNum); } else { if(fillOperator) { if(currentEvent != null) { logger.debug("Inheriting previous value for bin " + binNum); } } else { logger.debug("For non-fill operators, we do not inherit the previous bin's value " + binNum); currentEvent = null; } } if(currentEvent != null) { long epochSeconds = binNum*intervalSecs + intervalSecs/2; Timestamp eventTs = null; if(fillOperator) { logger.debug("For fill operators, we put the event time stamp in the center of the bin."); eventTs = TimeUtils.convertFromEpochSeconds(epochSeconds, 0); } else { logger.debug("This non-fill operators, we use the event's timestamp as is"); eventTs = currentEvent.getEventTimeStamp(); } POJOEvent pojoEvent = new POJOEvent(desc.getArchDBRType(), eventTs, currentEvent.getSampleValue(), ((AlarmInfo)currentEvent).getStatus(), ((AlarmInfo)currentEvent).getSeverity()); strm.add(pojoEvent.makeClone()); if(currentYear == -1) { // Initialize the current year as the year of the first bin with a value it it. currentYear = TimeUtils.computeYearForEpochSeconds(epochSeconds); FillsCollectorEventStream.this.desc.setYear(currentYear); } } } totalEvents = strm.size(); } @Override public boolean hasNext() { return currentEvent < totalEvents; } @Override public Event next() { Event next = strm.get(currentEvent); short eventYear = TimeUtils.computeYearForEpochSeconds(next.getEpochSeconds()); if(eventYear != currentYear) { logger.info("Detected a change in years eventYear " + eventYear + " and currentYear is " + eventYear); FillsCollectorEventStream.this.desc.setYear(eventYear); short tempCurrentYear = currentYear; currentYear = eventYear; throw new ChangeInYearsException(tempCurrentYear, eventYear); } currentEvent++; return next; } @Override public void remove() { throw new UnsupportedOperationException(); } } }