package org.yakindu.scr;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Runtime service for state machines to execute a run to completion step
* periodically.
*
*/
public class RuntimeService {
private static RuntimeService runtimeService;
private Timer timer = null;
private Map<Long, StatemachineTimerTask> timerTasks = new HashMap<Long, StatemachineTimerTask>();
private class StatemachineTimerTask extends TimerTask {
private List<IStatemachine> statemachineList = new LinkedList<IStatemachine>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private boolean isPaused = false;
@Override
public void run() {
lock.readLock().lock();
if (!isPaused) {
for (IStatemachine statemachine : statemachineList) {
statemachine.runCycle();
}
}
lock.readLock().unlock();
}
/**
* Adds the given state machine to the TimerTask.
*
* @param statemachine
* @return {@code true} if state machine is added properly.
*/
public boolean addStatemachine(IStatemachine statemachine) {
lock.writeLock().lock();
boolean ret = statemachineList.add(statemachine);
lock.writeLock().unlock();
return ret;
}
/**
* Removes the given state machine from the TimerTask.
*
* @param statemachine
* @return {@code true} if state machine is removed properly.
*/
public boolean removeStatemachine(IStatemachine statemachine) {
lock.writeLock().lock();
boolean ret = statemachineList.remove(statemachine);
lock.writeLock().unlock();
return ret;
}
public void pause() {
isPaused = true;
}
public void resume() {
isPaused = false;
}
}
private RuntimeService() {
// Not intended to be instantiated.
}
/**
* Returns the {@code RuntimeService} instance as singleton.
*
* @return The singleton {@code RuntimeService} instance
*/
public static RuntimeService getInstance() {
if (runtimeService == null) {
runtimeService = new RuntimeService();
}
return runtimeService;
}
/**
* Registers an {@link IStatemachine} for scheduled fixed rate execution
*
* @param statemachine
* - The state machine to execute
* @param cyclePeriod
* - the fixed rate cycle period for scheduling
* @return {@code true} if state machine is added properly.
*/
public boolean registerStatemachine(IStatemachine statemachine,
long cyclePeriod) {
if (timerTasks.containsKey(cyclePeriod)) {
// TimerTask for cycle time already existing -> add state machine
return timerTasks.get(cyclePeriod).addStatemachine(statemachine);
} else {
// Create new TimerTask for cycle period and add state machine
StatemachineTimerTask timerTask = new StatemachineTimerTask();
timerTasks.put(cyclePeriod, timerTask);
boolean ret = timerTask.addStatemachine(statemachine);
// Create a new Timer instance if runtime service was cancelled
// before
if (timer == null) {
timer = new Timer();
}
timer.scheduleAtFixedRate(timerTask, 0, cyclePeriod);
return ret;
}
}
/**
* Removes the given state machine from runtime service.
*
* @param statemachine
* - the state machine to be removed
* @param cyclePeriod
* - the scheduling cycle period of the state machine
* @return {@code true} if state machine is removed properly.
*/
public boolean unregisterStatemachine(IStatemachine statemachine,
long cyclePeriod) {
if (timerTasks.containsKey(cyclePeriod)) {
boolean ret = timerTasks.get(cyclePeriod).removeStatemachine(
statemachine);
return ret;
}
return false;
}
/**
* Cancels the execution of state machines for the given cycle period. This
* stops the execution of state machines which are registered for the given
* cycle period and cancels the executing {@link TimerTask}.
*
* @return {@code true} if poperly cancelled
*/
public boolean cancelAll(long cyclePeriod) {
if (timer != null && timerTasks.containsKey(cyclePeriod)) {
TimerTask task = timerTasks.get(cyclePeriod);
task.cancel();
timer.purge();
timerTasks.remove(cyclePeriod);
return true;
}
return false;
}
/**
* Pauses the execution of all state machines which are registered for the
* given cyclePeriod.
*
* @param cyclePeriod
* @return {@code true} if properly paused
*
*/
public boolean pauseAll(long cyclePeriod) {
if (timerTasks.containsKey(cyclePeriod)) {
timerTasks.get(cyclePeriod).pause();
return true;
}
return false;
}
/**
* Resumes the execution of all state machines which are registered for the
* given cyclePeriod.
*
* @param cyclePeriod
* @return {@code true} if properly resumed
*
*/
public boolean resumeAll(long cyclePeriod) {
if (timerTasks.containsKey(cyclePeriod)) {
timerTasks.get(cyclePeriod).resume();
return true;
}
return false;
}
/**
* Cancels the execution of all registered state machines. This cancels the
* executing {@link Timer} freeing all allocated resources and terminates
* all existing execution threads.
*/
public void cancelTimer() {
if (timer != null) {
timer.cancel();
timer.purge();
timerTasks.clear();
timer = null;
}
}
}