package org.epics.archiverappliance.retrieval.postprocessors; import java.io.IOException; import java.sql.Timestamp; import java.util.LinkedList; import java.util.concurrent.Callable; import javax.servlet.http.HttpServletRequest; 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.TimeSpan; import org.epics.archiverappliance.common.TimeUtils; import org.epics.archiverappliance.config.ArchDBRTypes; import org.epics.archiverappliance.config.PVTypeInfo; import org.epics.archiverappliance.data.ScalarValue; import org.epics.archiverappliance.engine.membuf.ArrayListEventStream; import org.epics.archiverappliance.retrieval.RemotableEventStreamDesc; /** * * <code>NCount</code> is a post processor which returns number of samples in * a selected time span. * * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a> * */ public class NCount implements PostProcessor, PostProcessorWithConsolidatedEventStream { private static final String IDENTITY = "ncount"; private static Logger logger = Logger.getLogger(NCount.class.getName()); private long startTime; private long endTime; private ArrayListEventStream data; private int count; private boolean countAddedToStream = false; @Override public String getIdentity() { return IDENTITY; } @Override public String getExtension() { return this.getIdentity(); } @Override public void initialize(String userarg, String pvName) throws IOException { //nothing } @Override public long estimateMemoryConsumption(String pvName, PVTypeInfo typeInfo, Timestamp start, Timestamp end, HttpServletRequest req) { this.startTime = start.getTime(); this.endTime = end.getTime(); return (long) typeInfo.getComputedStorageRate(); } @Override public Callable<EventStream> wrap(final Callable<EventStream> callable) { return new Callable<EventStream>() { @Override public EventStream call() throws Exception { Timestamp previousEventTimestamp = new Timestamp(1); try(EventStream strm = callable.call()) { RemotableEventStreamDesc org = (RemotableEventStreamDesc)strm.getDescription(); RemotableEventStreamDesc desc = new RemotableEventStreamDesc(org); desc.setArchDBRType(ArchDBRTypes.DBR_SCALAR_INT); if(data == null) { data = new ArrayListEventStream(1,desc); } for(Event e : strm) { if(e.getEventTimeStamp().after(previousEventTimestamp)) { previousEventTimestamp = e.getEventTimeStamp(); } else { if(logger.isDebugEnabled()) { logger.debug("Skipping older event " + TimeUtils.convertToHumanReadableString(e.getEventTimeStamp()) + " previous " + TimeUtils.convertToHumanReadableString(previousEventTimestamp)); } continue; } long s = e.getEventTimeStamp().getTime(); if (s < startTime || s > endTime) { logger.debug("Skipping event that is out of selected boundaries. Time: " + TimeUtils.convertToHumanReadableString(s)); } else { count++; } } return new ArrayListEventStream(0,desc); } } }; } @Override public LinkedList<TimeSpan> getBinTimestamps() { LinkedList<TimeSpan> list = new LinkedList<>(); if (data == null) return list; for (int i = 0; i < data.size() - 1; i++) { list.add(new TimeSpan(data.get(i).getEventTimeStamp(),data.get(i+1).getEventTimeStamp())); } return list; } @Override public EventStream getConsolidatedEventStream() { if(!countAddedToStream) { data.add(new POJOEvent(ArchDBRTypes.DBR_SCALAR_INT,new Timestamp(startTime),new ScalarValue<>(count),0,0)); countAddedToStream = true; } return data; } @Override public long getEndBinEpochSeconds() { return TimeUtils.convertToEpochSeconds(new Timestamp(endTime)); } @Override public long getStartBinEpochSeconds() { return TimeUtils.convertToEpochSeconds(new Timestamp(startTime)); } }