2 * Copyright (c) 2011 Big Switch Networks, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.util;
11 import java.util.concurrent.ScheduledExecutorService;
12 import java.util.concurrent.TimeUnit;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
18 * This allows you to represent a task that should be queued for future execution
19 * but where you only want the task to complete once in response to some sequence
20 * of events. For example, if you get a change notification and want to reload state,
21 * you only want to reload the state once, at the end, and don't want to queue
22 * an update for every notification that might come in.
24 * The semantics are as follows:
25 * * If the task hasn't begun yet, do not queue a new task
26 * * If the task has begun, set a bit to restart it after the current task finishes
28 public class SingletonTask {
29 protected static final Logger LOG =
30 LoggerFactory.getLogger(SingletonTask.class);
32 protected static class SingletonTaskContext {
33 protected boolean taskShouldRun = false;
34 protected boolean taskRunning = false;
36 protected SingletonTaskWorker waitingTask = null;
39 protected static class SingletonTaskWorker implements Runnable {
41 boolean canceled = false;
42 long nextschedule = 0;
44 public SingletonTaskWorker(SingletonTask parent) {
51 synchronized (parent.context) {
52 if (canceled || !parent.context.taskShouldRun)
55 parent.context.taskRunning = true;
56 parent.context.taskShouldRun = false;
61 } catch (Exception e) {
62 LOG.error("Exception while executing task", e);
65 synchronized (parent.context) {
66 parent.context.taskRunning = false;
68 if (parent.context.taskShouldRun) {
69 long now = System.nanoTime();
70 if ((nextschedule <= 0 || (nextschedule - now) <= 0)) {
71 parent.ses.execute(this);
73 parent.ses.schedule(this,
75 TimeUnit.NANOSECONDS);
82 protected SingletonTaskContext context = new SingletonTaskContext();
83 protected Runnable task;
84 protected ScheduledExecutorService ses;
88 * Construct a new SingletonTask for the given runnable. The context
89 * is used to manage the state of the task execution and can be shared
90 * by more than one instance of the runnable.
94 public SingletonTask(ScheduledExecutorService ses,
102 * Schedule the task to run if there's not already a task scheduled
103 * If there is such a task waiting that has not already started, it
104 * cancel that task and reschedule it to run at the given time. If the
105 * task is already started, it will cause the task to be rescheduled once
106 * it completes to run after delay from the time of reschedule.
108 * @param delay the delay in scheduling
109 * @param unit the timeunit of the delay
111 public void reschedule(long delay, TimeUnit unit) {
112 boolean needQueue = true;
113 SingletonTaskWorker stw = null;
115 synchronized (context) {
116 if (context.taskRunning || context.taskShouldRun) {
117 if (context.taskRunning) {
118 // schedule to restart at the right time
120 long now = System.nanoTime();
122 now + TimeUnit.NANOSECONDS.convert(delay, unit);
123 context.waitingTask.nextschedule = then;
125 context.waitingTask.nextschedule = 0;
129 // cancel and requeue
130 context.waitingTask.canceled = true;
131 context.waitingTask = null;
135 context.taskShouldRun = true;
138 stw = context.waitingTask = new SingletonTaskWorker(this);
146 ses.schedule(stw, delay, unit);