/** Copyright (c) 2012-2015 committers of YAKINDU and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html Contributors: committers of YAKINDU - initial API and implementation �*/ package traffic.light; 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 timerTasks = new HashMap(); private class StatemachineTimerTask extends TimerTask { private List statemachineList = new LinkedList(); 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 which should 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; } } }