package nl.tno.sensorstorm.timer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import nl.tno.sensorstorm.api.annotation.MetaParticleHandlerDeclaration;
import nl.tno.sensorstorm.api.particles.DataParticle;
import nl.tno.sensorstorm.api.particles.MetaParticle;
import nl.tno.sensorstorm.api.particles.Particle;
import nl.tno.sensorstorm.api.processing.MetaParticleHandler;
import nl.tno.sensorstorm.api.processing.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This handler handles TimerTickParticles and uses them to service single and
* recurring requests from the related operation to the handler.
*
* @author waaijbdvd
*
*/
@MetaParticleHandlerDeclaration(metaParticle = TimerTickParticle.class)
public class TimerParticleHandler implements MetaParticleHandler,
TimerControllerInterface, Serializable {
protected Logger logger = LoggerFactory
.getLogger(TimerParticleHandler.class);
private static final long serialVersionUID = 8622533504407023168L;
private RecurringTask recurringTask = null;
private SingleTask singleTask = null;
/**
* Connect the operation to this Timer
*/
@Override
public void init(Operation operation) {
if (operation instanceof TimerTaskInterface) {
((TimerTaskInterface) operation).setTimerController(this);
} else {
logger.error("Operation "
+ operation.getClass().getName()
+ " can not be connected to a timer. It does not implements the TimerTaskInterface");
}
logger.info("TimerParticleHandler initiated for operation "
+ operation.getClass().getName());
}
// public List<Particle> oldhandleMetaParticle(MetaParticle metaParticle) {
// List<Particle> result = new ArrayList<Particle>();
// if (metaParticle instanceof TimerTickParticle) {
// TimerTickParticle timerParticle = (TimerTickParticle) metaParticle;
// long timestamp = timerParticle.getTimestamp();
//
// // do first the single task, to give it the possibility to schedule
// // a recurring task at the current moment
// result.addAll(executeSingleTasks(timestamp));
// result.addAll(executeRecurringTasks(timestamp));
//
// // TODO fix that all new registered tasks are all being processed
// // within the current moment
// }
// return result;
// }
@Override
public List<Particle> handleMetaParticle(MetaParticle metaParticle) {
List<Particle> result = new ArrayList<Particle>();
if (metaParticle instanceof TimerTickParticle) {
TimerTickParticle timerParticle = (TimerTickParticle) metaParticle;
long timestamp = timerParticle.getTimestamp();
// Keep processing registered tasks until no new tasks for this
// moment are added anymore in the timerTask methods
List<Particle> executeSingleTasks;
List<Particle> executeRecurringTasks;
do {
executeSingleTasks = executeSingleTasks(timestamp);
executeRecurringTasks = executeRecurringTasks(timestamp);
// do first the single task, to give it the possibility to
// schedule
// a recurring task at the current moment
if (executeSingleTasks.size() > 0) {
result.addAll(executeSingleTasks);
}
if (executeRecurringTasks.size() > 0) {
result.addAll(executeRecurringTasks);
}
} while ((executeSingleTasks.size() > 0)
&& (executeRecurringTasks.size() > 0));
}
return result;
}
/**
* Executes all recurring tasks pending before timestamp.
*
* @param timestamp
* @return Returns an empty list or a list with one or more particles to be
* outputed.
*/
protected List<Particle> executeRecurringTasks(long timestamp) {
List<Particle> result = new ArrayList<Particle>();
if (recurringTask != null) {
if (recurringTask.timerFreq != 0) {
if (recurringTask.lastTimestamp == 0) {
recurringTask.lastTimestamp = timestamp;
}
while (timestamp - recurringTask.lastTimestamp >= recurringTask.timerFreq) {
recurringTask.lastTimestamp = recurringTask.lastTimestamp
+ recurringTask.timerFreq;
List<DataParticle> outputParticles = recurringTask.recurringTimerTaskHandler
.doTimerRecurringTask(recurringTask.lastTimestamp);
if (outputParticles != null) {
result.addAll(outputParticles);
}
}
}
}
return result;
}
/**
* Executes all single tasks pending before timestamp.
*
* @param timestamp
* @return Returns an empty list or a list with one or more particles to be
* outputed.
*/
protected List<Particle> executeSingleTasks(long timestamp) {
List<Particle> result = new ArrayList<Particle>();
if (singleTask != null) {
if (singleTask.wakeupTime != 0) {
while ((singleTask.wakeupTime != 0)
&& (timestamp >= singleTask.wakeupTime)) {
long timerTaskTimestamp = singleTask.wakeupTime;
singleTask.wakeupTime = 0;
List<DataParticle> outputParticles = singleTask.singleTimerTaskHandler
.doTimerSingleTask(timerTaskTimestamp);
if (outputParticles != null) {
result.addAll(outputParticles);
}
}
}
}
return result;
}
@Override
public void registerOperationForRecurringTimerTask(long timerFreq,
TimerTaskInterface timerTask) {
recurringTask = new RecurringTask(timerFreq, 0, timerTask);
}
@Override
public void registerOperationForSingleTimerTask(long wakeupTime,
TimerTaskInterface timerTask) {
singleTask = new SingleTask(wakeupTime, timerTask);
}
}
class RecurringTask {
public long timerFreq;
public long lastTimestamp;
public TimerTaskInterface recurringTimerTaskHandler;
public RecurringTask(long recurringTimerFreq, long lastRecurringTimestamp,
TimerTaskInterface recurringTimerTaskInterface) {
this.timerFreq = recurringTimerFreq;
this.lastTimestamp = lastRecurringTimestamp;
this.recurringTimerTaskHandler = recurringTimerTaskInterface;
}
}
class SingleTask {
public long wakeupTime;
public TimerTaskInterface singleTimerTaskHandler;
public SingleTask(long sleepTimeSingleWakeup,
TimerTaskInterface recurringTimerTaskInterface) {
this.wakeupTime = sleepTimeSingleWakeup;
this.singleTimerTaskHandler = recurringTimerTaskInterface;
}
}