/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.timecache; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.diirt.datasource.timecache.source.DataSource; import org.diirt.datasource.timecache.util.CacheHelper; import org.diirt.datasource.timecache.util.IntervalsList; import org.diirt.util.time.TimeInterval; /** * Retrieves chunks from the specified {@link DataSource}, channel name and * {@link TimeInterval}. Polls chunks from the source until the * {@link Timestamp} of the last received {@link Data} is superior to the end of * the defined {@link TimeInterval}. * @author Fred Arnaud (Sopra Group) - ITER */ public class DataRequestThread extends Thread { private static AtomicInteger idCounter = new AtomicInteger(0); private final Integer requestID; private final String channelName; private final DataSource source; private TimeInterval interval; private Instant lastReceived; private List<DataRequestListener> listeners; public DataRequestThread(String channelName, DataSource source, TimeInterval interval) throws Exception { if (channelName == null || channelName.isEmpty() || source == null || interval == null) throw new Exception("null or empty argument not allowed"); this.requestID = idCounter.getAndIncrement(); this.listeners = new ArrayList<DataRequestListener>(); this.channelName = channelName; this.source = source; this.interval = CacheHelper.arrange(interval); this.lastReceived = this.interval.getStart(); } /** {@inheritDoc} */ @Override public void run() { if (interval.getStart() == null) { notifyComplete(); return; } DataChunk currentChunk = source.getData(channelName, interval.getStart()); boolean process = true; while (process) { if (currentChunk == null || currentChunk.isEmpty() || !CacheHelper.intersects(interval, currentChunk.getInterval())) { process = false; break; } else { lastReceived = currentChunk.getInterval().getEnd(); notifyNewData(currentChunk); if (!currentChunk.isFull() || !interval.contains(lastReceived)) { process = false; break; } } currentChunk = source.getData(channelName, lastReceived.plus(IntervalsList.minDuration)); } notifyComplete(); } // Notify the listeners that a new chunk is available private void notifyNewData(DataChunk chunk) { for (DataRequestListener l : listeners) l.newData(chunk, this); } // Notify the listeners that the thread has finished requesting samples private void notifyComplete() { for (DataRequestListener l : listeners) l.intervalComplete(this); } /** Add a {@link DataRequestListener}. */ public void addListener(DataRequestListener l) { if (l != null) listeners.add(l); } /** Remove a {@link DataRequestListener}. */ public void removeListener(DataRequestListener l) { if (l != null) listeners.remove(l); } public TimeInterval getInterval() { return interval; } public void setInterval(TimeInterval interval) { this.interval = interval; } public String getChannelName() { return channelName; } public DataSource getSource() { return source; } public Instant getLastReceived() { return lastReceived; } public Integer getRequestID() { return requestID; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((requestID == null) ? 0 : requestID.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DataRequestThread other = (DataRequestThread) obj; if (requestID == null) { if (other.requestID != null) return false; } else if (!requestID.equals(other.requestID)) return false; return true; } }