blob: 1118568fb6bc86822614e302bfc7f185dd977ccc [file] [log] [blame]
jaegonkim6a7b5242018-09-12 23:09:42 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.workflow.api;
17
18import java.util.Date;
Ray Milkeyfe6afd82018-11-26 14:03:20 -080019import java.util.Objects;
jaegonkim6a7b5242018-09-12 23:09:42 +090020import java.util.PriorityQueue;
21import java.util.Timer;
22import java.util.TimerTask;
23
24/**
25 * Class for time chain timer.
26 */
27public class TimerChain {
28
29 private PriorityQueue<TimerChainTask> taskQueue = new PriorityQueue<>();
30
31 private Timer impendingTimer;
32 private TimerChainTask impendingTask;
33
34 /**
35 * Schedules timer event.
36 * @param afterMs millisecond which time event happens.
37 * @param runnable runnable to be executed after 'afterMs'
38 */
39 public void schedule(long afterMs, Runnable runnable) {
40 schedule(new Date((new Date()).getTime() + afterMs), runnable);
41 }
42
43 /**
44 * Schedules timer event.
45 * @param date date which timer event happens.
46 * @param runnable runnable to be executed on 'date'
47 */
48 public void schedule(Date date, Runnable runnable) {
49 schedule(new TimerChainTask(this, date, runnable));
50 }
51
52 /**
53 * Schedule timer chain task.
54 * @param task task to be scheduled.
55 */
56 private void schedule(TimerChainTask task) {
57 synchronized (this) {
58 if (taskQueue.size() == 0) {
59 scheduleImpending(task);
60 return;
61 }
62
63 if (task.date().getTime() < head().date().getTime()) {
64 impendingTimer.cancel();
65 impendingTask.cancel();
66 TimerChainTask prevImpendingTask = pop().copy();
67 taskQueue.offer(prevImpendingTask);
68
69 scheduleImpending(task);
70 } else {
71 taskQueue.offer(task);
72 }
73 }
74 }
75
76 /**
77 * Schedule impending timer task.
78 * @param task impending timer chain task
79 * @return timer chain task
80 */
81 private TimerChainTask scheduleImpending(TimerChainTask task) {
82 taskQueue.offer(task);
83 Timer timer = new Timer();
84 this.setImpendingTask(task);
85 this.setImpendingTimer(timer);
86 timer.schedule(task, task.date());
87 return task;
88 }
89
90 /**
91 * Gets impending timer.
92 * @return impending timer
93 */
94 public Timer implendingTimer() {
95 return impendingTimer;
96 }
97
98 /**
99 * Sets impending timer.
100 * @param impendingTimer impending timer
101 */
102 public void setImpendingTimer(Timer impendingTimer) {
103 this.impendingTimer = impendingTimer;
104 }
105
106 /**
107 * Gets impending timer task.
108 * @return impending timer task
109 */
110 public TimerTask impendingTask() {
111 return impendingTask;
112 }
113
114 /**
115 * Sets impending timer task.
116 * @param impendingTask impending timer task
117 */
118 public void setImpendingTask(TimerChainTask impendingTask) {
119 this.impendingTask = impendingTask;
120 }
121
122 /**
123 * Gets head of timer chain task queue.
124 * @return timer chain task
125 */
126 public TimerChainTask head() {
127 if (taskQueue.size() > 0) {
128 return taskQueue.peek();
129 } else {
130 return null;
131 }
132 }
133
134 /**
135 * Pops head of timer chain task queue.
136 * @return timer chain task
137 */
138 public TimerChainTask pop() {
139 if (taskQueue.size() > 0) {
140 return taskQueue.poll();
141 } else {
142 return null;
143 }
144 }
145
146 /**
147 * Class for timer chain task.
148 */
149 public static class TimerChainTask extends TimerTask implements Comparable<TimerChainTask> {
150
151 private final TimerChain timerchain;
152 private final Date date;
153 private final Runnable runnable;
154
155 /**
156 * Constructor of timer chain task.
157 * @param timerchain timer chain
158 * @param date date to be scheduled
159 * @param runnable runnable to be executed by timer
160 */
161 public TimerChainTask(TimerChain timerchain, Date date, Runnable runnable) {
162 this.timerchain = timerchain;
163 this.date = date;
164 this.runnable = runnable;
165 }
166
167 /**
168 * Gets date.
169 * @return date of timer chain task
170 */
171 public Date date() {
172 return this.date;
173 }
174
175 /**
176 * Gets runnable.
177 * @return runnable of timer chain task
178 */
179 public Runnable runnable() {
180 return this.runnable;
181 }
182
183 @Override
184 public void run() {
185
186 TimerChainTask nextTask;
187 synchronized (timerchain) {
188 if (timerchain.impendingTask() != this) {
189 System.out.println("Invalid impendingTask");
190 runnable().run();
191 return;
192 }
193
194 timerchain.implendingTimer().cancel();
195 timerchain.pop();
196
197 nextTask = timerchain.head();
198
199 if (nextTask != null) {
200 Timer nextTimer = new Timer();
201 this.timerchain.setImpendingTask(nextTask);
202 this.timerchain.setImpendingTimer(nextTimer);
203 nextTimer.schedule(nextTask, nextTask.date());
204 }
205 }
206
207 runnable().run();
208
209 }
210
211 @Override
212 public int compareTo(TimerChainTask target) {
213 return date().compareTo(target.date());
214 }
215
Ray Milkeyfe6afd82018-11-26 14:03:20 -0800216 @Override
217 public boolean equals(Object o) {
218 if (this == o) {
219 return true;
220 }
221 if (!(o instanceof TimerChainTask)) {
222 return false;
223 }
224 TimerChainTask that = (TimerChainTask) o;
225
226 return this.date().equals(that.date());
227 }
228
229 @Override
230 public int hashCode() {
231 return Objects.hash(date);
232 }
233
jaegonkim6a7b5242018-09-12 23:09:42 +0900234 /**
235 * Copies timer chain task.
236 * @return timer chain task
237 */
238 public TimerChainTask copy() {
239 return new TimerChainTask(timerchain, date, runnable);
240 }
241 }
242}