summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java')
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java522
1 files changed, 0 insertions, 522 deletions
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
deleted file mode 100644
index 8fb008e8..00000000
--- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onlab.util;
-
-import com.google.common.collect.Lists;
-import org.onlab.junit.TestUtils;
-import org.slf4j.Logger;
-
-import java.util.Date;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.TimerTask;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.junit.TestTools.delay;
-import static org.slf4j.LoggerFactory.getLogger;
-
-
-/**
- * Provides manually scheduled timer utility. All schedulable methods are subject to overflow (you can set a period of
- * max long). Additionally if a skip skips a period of time greater than one period for a periodic task that task will
- * only be executed once for that skip and scheduled it's period after the last execution.
- */
-public class ManuallyAdvancingTimer extends java.util.Timer {
-
- /* States whether or not the static values from timer task have been set ensures population will only occur once.*/
- private boolean staticsPopulated = false;
-
- /* Virgin value from timer task */
- private int virginState;
-
- /* Scheduled value from timer task */
- private int scheduledState;
-
- /* Executed value from timer task */
- private int executedState;
-
- /* Cancelled value from timer task */
- private int cancelledState;
-
- private final Logger logger = getLogger(getClass());
-
- /* Service for executing timer tasks */
- private final ExecutorService executorService = Executors.newSingleThreadExecutor();
-
- /* Internal time representation independent of system time, manually advanced */
- private final TimerKeeper timerKeeper = new TimerKeeper();
-
- /* Data structure for tracking tasks */
- private final TaskQueue queue = new TaskQueue();
-
- /* Whether execution should execute on the executor thread or the calling thread. */
- private final boolean runLocally;
-
- public ManuallyAdvancingTimer(boolean runLocally) {
- this.runLocally = runLocally;
- }
-
-
- @Override
- public void schedule(TimerTask task, long delay) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
- timerKeeper.currentTimeInMillis() - delay, 0)) {
- logger.error("Failed to submit task");
- }
- }
-
- @Override
- public void schedule(TimerTask task, Date time) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, time.getTime(), 0)) {
- logger.error("Failed to submit task");
- }
- }
-
- @Override
- public void schedule(TimerTask task, long delay, long period) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
- timerKeeper.currentTimeInMillis() - delay, period)) {
- logger.error("Failed to submit task");
- }
- }
-
- @Override
- public void schedule(TimerTask task, Date firstTime, long period) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, firstTime.getTime(), period)) {
- logger.error("Failed to submit task");
- }
- }
-
- /*################################################WARNING################################################*/
- /* Schedule at fixed rate methods do not work exactly as in the java timer. They are clones of the periodic
- *scheduling methods. */
- @Override
- public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay :
- timerKeeper.currentTimeInMillis() - delay, period)) {
- logger.error("Failed to submit task");
- }
- }
-
- @Override
- public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
- if (!staticsPopulated) {
- populateStatics(task);
- }
- if (!submitTask(task, firstTime.getTime(), period)) {
- logger.error("Failed to submit task");
- }
- }
-
- @Override
- public void cancel() {
- executorService.shutdown();
- queue.clear();
- }
-
- @Override
- public int purge() {
- return queue.removeCancelled();
- }
-
- /**
- * Returns the virtual current time in millis.
- *
- * @return long representing simulated current time.
- */
- public long currentTimeInMillis() {
- return timerKeeper.currentTimeInMillis();
- }
-
- /**
- * Returns the new simulated current time in millis after advancing the absolute value of millis to advance.
- * Triggers event execution of all events scheduled for execution at times up to and including the returned time.
- * Passing in the number zero has no effect.
- *
- * @param millisToAdvance the number of millis to advance.
- * @return a long representing the current simulated time in millis
- */
- public long advanceTimeMillis(long millisToAdvance) {
- return timerKeeper.advanceTimeMillis(millisToAdvance);
- }
-
- /**
- * Advances the virtual time a certain number of millis triggers execution delays a certain amount to
- * allow time for execution. If runLocally is true then all real time delays are ignored.
- *
- * @param virtualTimeAdvance the time to be advances in millis of simulated time.
- * @param realTimeDelay the time to delay in real time to allow for processing.
- */
- public void advanceTimeMillis(long virtualTimeAdvance, int realTimeDelay) {
- timerKeeper.advanceTimeMillis(virtualTimeAdvance);
- if (!runLocally) {
- delay(realTimeDelay);
- }
- }
-
- /**
- * Sets up the task and submits it to the queue.
- *
- * @param task the task to be added to the queue
- * @param runtime the first runtime of the task
- * @param period the period between runs thereafter
- * @return returns true if the task was successfully submitted, false otherwise
- */
- private boolean submitTask(TimerTask task, long runtime, long period) {
- checkNotNull(task);
- try {
- TestUtils.setField(task, "state", scheduledState);
- TestUtils.setField(task, "nextExecutionTime", runtime);
- TestUtils.setField(task, "period", period);
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- return false;
- }
- queue.insertOrdered(task);
- return true;
- }
-
- /**
- * Executes the given task (only if it is in the scheduled state) and proceeds to reschedule it or mark it as
- * executed. Does not remove from the queue (this must be done outside).
- *
- * @param task the timer task to be executed
- */
- private boolean executeTask(TimerTask task) {
- checkNotNull(task);
- int currentState;
- try {
- currentState = TestUtils.getField(task, "state");
- } catch (TestUtils.TestUtilsException e) {
- logger.error("Could not get state of task.");
- e.printStackTrace();
- return false;
- }
- //If cancelled or already executed stop here.
- if (currentState == executedState || currentState == cancelledState) {
- return false;
- } else if (currentState == virginState) {
- logger.error("Task was set for execution without being scheduled.");
- return false;
- } else if (currentState == scheduledState) {
- long period;
-
- try {
- period = TestUtils.getField(task, "period");
- } catch (TestUtils.TestUtilsException e) {
- logger.error("Could not read period of task.");
- e.printStackTrace();
- return false;
- }
- //Period of zero means one time execution.
- if (period == 0) {
- try {
- TestUtils.setField(task, "state", executedState);
- } catch (TestUtils.TestUtilsException e) {
- logger.error("Could not set executed state.");
- e.printStackTrace();
- return false;
- }
- if (runLocally) {
- task.run();
- } else {
- executorService.execute(task);
- }
- return true;
- } else {
- //Calculate next execution time, using absolute value of period
- long nextTime = (period > 0) ? (timerKeeper.currentTimeInMillis() + period) :
- (timerKeeper.currentTimeInMillis() - period);
- try {
- TestUtils.setField(task, "nextExecutionTime", nextTime);
- } catch (TestUtils.TestUtilsException e) {
- logger.error("Could not set next execution time.");
- e.printStackTrace();
- return false;
- }
- //Schedule next execution
- queue.insertOrdered(task);
- if (runLocally) {
- task.run();
- } else {
- executorService.execute(task);
- }
- return true;
- }
- }
- logger.error("State property of {} is in an illegal state and did not execute.", task);
- return false;
- }
-
- /**
- * Executes all tasks in the queue scheduled for execution up to and including the current time.
- *
- * @return the total number of tasks run, -1 if failure
- */
- private int executeEventsUpToPresent() {
- int totalRun = 0;
- if (queue.isEmpty()) {
- return -1;
- }
- TimerTask currTask = queue.peek();
- long currExecTime;
- try {
- currExecTime = TestUtils.getField(currTask, "nextExecutionTime");
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- throw new RuntimeException("Could not get nextExecutionTime");
- }
- while (currExecTime <= timerKeeper.currentTimeInMillis()) {
- if (executeTask(queue.pop())) {
- totalRun++;
- }
- if (queue.isEmpty()) {
- break;
- }
- currTask = queue.peek();
- try {
- currExecTime = TestUtils.getField(currTask, "nextExecutionTime");
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- throw new RuntimeException("Could not get nextExecutionTime");
- }
- }
- return totalRun;
- }
-
- /**
- * Populates the static fields from timer task. Should only be called once.
- */
- private void populateStatics(TimerTask task) {
- try {
- virginState = TestUtils.getField(task, "VIRGIN");
- scheduledState = TestUtils.getField(task, "SCHEDULED");
- executedState = TestUtils.getField(task, "EXECUTED");
- cancelledState = TestUtils.getField(task, "CANCELLED");
- staticsPopulated = true;
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * A class used to maintain the virtual time.
- */
- private class TimerKeeper {
-
- private long currentTime = 0;
-
- /**
- * Returns the virtual current time in millis.
- *
- * @return long representing simulated current time.
- */
- long currentTimeInMillis() {
- return currentTime;
- }
-
- /**
- * Returns the new simulated current time in millis after advancing the absolute value of millis to advance.
- * Triggers event execution of all events scheduled for execution at times up to and including the returned
- * time. Passing in the number zero has no effect.
- *
- * @param millisToAdvance the number of millis to advance.
- * @return a long representing the current simulated time in millis
- */
- long advanceTimeMillis(long millisToAdvance) {
- currentTime = (millisToAdvance >= 0) ? (currentTime + millisToAdvance) : (currentTime - millisToAdvance);
- if (millisToAdvance != 0) {
- executeEventsUpToPresent();
- }
- return currentTime;
- }
- }
-
- /**
- * A queue backed by a linked list. Keeps elements sorted in ascending order of execution time. All calls are safe
- * even on empty queue's.
- */
- private class TaskQueue {
- private final LinkedList<TimerTask> taskList = Lists.newLinkedList();
-
- /**
- * Adds the task to the queue in ascending order of scheduled execution. If execution time has already passed
- * execute immediately.
- *
- * @param task the task to be added to the queue
- */
- void insertOrdered(TimerTask task) {
- //Using O(N) insertion because random access is expensive in linked lists worst case is 2N links followed
- // for binary insertion vs N for simple insertion.
- checkNotNull(task);
- if (!staticsPopulated) {
- populateStatics(task);
- }
- long insertTime;
- try {
- insertTime = TestUtils.getField(task, "nextExecutionTime");
- TestUtils.setField(task, "state", scheduledState);
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- return;
- }
- //If the task was scheduled in the past or for the current time run it immediately and do not add to the
- // queue, subsequent executions will be scheduled as normal
- if (insertTime <= timerKeeper.currentTimeInMillis()) {
- executeTask(task);
- return;
- }
-
- Iterator<TimerTask> iter = taskList.iterator();
- int positionCounter = 0;
- long nextTaskTime;
- TimerTask currentTask;
- while (iter.hasNext()) {
- currentTask = iter.next();
- try {
- nextTaskTime = TestUtils.getField(currentTask, "nextExecutionTime");
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- return;
- }
- if (insertTime < nextTaskTime) {
- taskList.add(positionCounter, task);
- return;
- }
- positionCounter++;
- }
- taskList.addLast(task);
- }
-
- /**
- * Returns the first item in the queue (next scheduled for execution) without removing it, returns null if the
- * queue is empty.
- *
- * @return the next TimerTask to run or null if the queue is empty
- */
- TimerTask peek() {
- if (taskList.isEmpty()) {
- return null;
- }
- return taskList.getFirst();
- }
-
- /**
- * Returns and removes the first item in the queue or null if it is empty.
- *
- * @return the first element of the queue or null if the queue is empty
- */
- TimerTask pop() {
- if (taskList.isEmpty()) {
- return null;
- }
- return taskList.pop();
- }
-
- /**
- * Performs a sort on the set of timer tasks, earliest task is first. Does nothing if queue is empty.
- */
- void sort() {
- if (taskList.isEmpty()) {
- return;
- }
- taskList.sort((o1, o2) -> {
- checkNotNull(o1);
- checkNotNull(o2);
- long executionTimeOne;
- long executionTimeTwo;
- try {
- executionTimeOne = TestUtils.getField(o1, "nextExecutionTime");
- executionTimeTwo = TestUtils.getField(o2, "nextExecutionTime");
- } catch (TestUtils.TestUtilsException e) {
- e.printStackTrace();
- throw new RuntimeException("Could not get next execution time.");
- }
- if (executionTimeOne == executionTimeTwo) {
- return 0;
- } else if (executionTimeOne < executionTimeTwo) {
- return -1;
- } else {
- return 1;
- }
- });
- }
-
- /**
- * Returns whether the queue is currently empty.
- *
- * @return true if the queue is empty, false otherwise
- */
- boolean isEmpty() {
- return taskList.isEmpty();
- }
-
- /**
- * Clears the underlying list of the queue.
- */
- void clear() {
- taskList.clear();
- }
-
- /**
- * Removes all cancelled tasks from the queue. Has no effect on behavior.
- *
- * @return returns the total number of items removed, -1 if list is empty or failure occurs.
- */
- int removeCancelled() {
- if (taskList.isEmpty()) {
- return -1;
- }
- int removedCount = 0;
- Iterator<TimerTask> taskIterator = taskList.iterator();
- TimerTask currTask;
- int currState;
- while (taskIterator.hasNext()) {
- currTask = taskIterator.next();
- try {
- currState = TestUtils.getField(currTask, "state");
- } catch (TestUtils.TestUtilsException e) {
- logger.error("Could not get task state.");
- e.printStackTrace();
- return -1;
- }
- if (currState == cancelledState) {
- removedCount++;
- taskIterator.remove();
- }
- }
- return removedCount;
- }
- }
-}