package simulator.interfaces.timers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.Term;
import models.dataConstraintModel.JsonTerm;
import models.dataConstraintModel.MapTerm;
import models.dataConstraintModel.ResourcePath;
import models.dataFlowModel.DataTransferChannel;
import simulator.Event;
import simulator.Resource;
import simulator.Simulator;
import simulator.SystemState;
import simulator.interfaces.INativeReceiver;
public class TimerService implements INativeReceiver {
public final String timersUpdatedChannelName = "TimersUpdated";
public final String timerEventChannelName = "TimerEvent";
protected final Simulator simulator;
protected final Map<String, ScheduledThreadPoolExecutor> timers;
protected DataTransferChannel timersUpdatedChannel;
protected DataTransferChannel timerEventChannel;
public TimerService(Simulator simulator) {
this.simulator = simulator;
timers = new HashMap<>();
timersUpdatedChannel = (DataTransferChannel) simulator.getModel().getChannel(timersUpdatedChannelName);
timerEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(timerEventChannelName);
simulator.addNativeReceiver(this, timersUpdatedChannel);
}
@Override
public void onReceiveFromModel(Event event, SystemState nextSystemState) {
Expression message = event.getMessage();
if (message instanceof Term && ((Term) message).getChildren().size() >= 2) {
Expression curTimersExp = ((Term) message).getChild(0);
Expression nextTimersExp = ((Term) message).getChild(1);
if (curTimersExp instanceof MapTerm && nextTimersExp instanceof MapTerm) {
MapTerm curTimers = (MapTerm) curTimersExp;
MapTerm nextTimers = (MapTerm) nextTimersExp;
Set<String> oldTidSet = new HashSet<>(curTimers.keySet());
Set<String> newTidSet = new HashSet<>(nextTimers.keySet());
oldTidSet.removeAll(nextTimers.keySet());
newTidSet.removeAll(curTimers.keySet());
if (!oldTidSet.isEmpty() || !newTidSet.isEmpty()) {
// If the set of timers is changed.
// Remove old timers and their native receivers.
for (String tid: oldTidSet) {
ScheduledThreadPoolExecutor timer = timers.get(tid);
timer.shutdown();
timers.remove(tid);
}
// Add new timers.
Resource timersResource = nextSystemState.getResource(event.getInputResource().getResourceIdentifier());
for (String tid: newTidSet) {
Expression value = nextTimers.get(tid);
if (value instanceof JsonTerm) {
JsonTerm timerValue = (JsonTerm) value;
Resource timerResource = timersResource.getChildrenMap().get(tid);
// Add a timer.
Expression intervalExp = timerValue.get("interval");
long interval = Long.parseLong(((Constant) intervalExp).toString());
ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(0);
timers.put(tid, timer);
// Connect Java timer and model.
ResourcePath resPath = timerEventChannel.getOutputResources().iterator().next();
TimerEventSender sender = new TimerEventSender(simulator, timerEventChannel, resPath, timerResource); // timer => timerResource
timer.scheduleAtFixedRate(sender, 0, interval, TimeUnit.MILLISECONDS);
}
}
}
}
}
}
public class TimerStart implements INativeReceiver {
public final String timerStartChannelName = "TimerStart";
protected DataTransferChannel timerStartChannel;
protected DataTransferChannel timerEventChannel;
public TimerStart() {
timerStartChannel = (DataTransferChannel) simulator.getModel().getChannel(timerStartChannelName);
timerEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(timerEventChannelName);
simulator.addNativeReceiver(this, timerStartChannel);
}
@Override
public void onReceiveFromModel(Event event, SystemState nextSystemState) {
Expression message = event.getMessage();
if (message instanceof Term && ((Term) message).getChildren().size() >= 1) {
Expression tidExp = event.getInputResource().getResourceIdentifier().getLastParam();
Expression intervalExp = ((Term) message).getChild(0);
if (tidExp instanceof Constant && intervalExp instanceof Constant) {
String tid = ((Constant) tidExp).toString();
long interval = Long.parseLong(((Constant) intervalExp).toString());
ScheduledThreadPoolExecutor timer = timers.get(tid);
TimerEventSender sender = new TimerEventSender(simulator, timerEventChannel, event.getInputResourcePath(), event.getInputResource());
timer.scheduleAtFixedRate(sender, 0, interval, TimeUnit.MILLISECONDS);
}
}
}
}
public class TimerClear implements INativeReceiver {
public final String timerClearChannelName = "TimerClear";
protected DataTransferChannel timerClearChannel;
public TimerClear() {
timerClearChannel = (DataTransferChannel) simulator.getModel().getChannel(timerClearChannelName);
simulator.addNativeReceiver(this, timerClearChannel);
}
@Override
public void onReceiveFromModel(Event event, SystemState nextSystemState) {
Expression message = event.getMessage();
if (message instanceof Term && ((Term) message).getChildren().size() >= 1) {
Expression tidExp = event.getInputResource().getResourceIdentifier().getLastParam();
if (tidExp instanceof Constant) {
String tid = ((Constant) tidExp).toString();
ScheduledThreadPoolExecutor timer = timers.get(tid);
timer.shutdown();
timers.remove(tid);
}
}
}
}
}