blob: afa2ac63df9e5f92d212a4d342472a1f08c1cf13 [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 /**
jaegonkime0f45b52018-10-09 20:23:26 +090035 * Constructor of timer chain.
36 */
37 public TimerChain() {
38
39 }
40
41 /**
jaegonkim6a7b5242018-09-12 23:09:42 +090042 * Schedules timer event.
43 * @param afterMs millisecond which time event happens.
44 * @param runnable runnable to be executed after 'afterMs'
45 */
46 public void schedule(long afterMs, Runnable runnable) {
47 schedule(new Date((new Date()).getTime() + afterMs), runnable);
48 }
49
50 /**
51 * Schedules timer event.
52 * @param date date which timer event happens.
53 * @param runnable runnable to be executed on 'date'
54 */
55 public void schedule(Date date, Runnable runnable) {
56 schedule(new TimerChainTask(this, date, runnable));
57 }
58
59 /**
60 * Schedule timer chain task.
61 * @param task task to be scheduled.
62 */
63 private void schedule(TimerChainTask task) {
64 synchronized (this) {
jaegonkime0f45b52018-10-09 20:23:26 +090065 if (taskQueue.isEmpty()) {
jaegonkim6a7b5242018-09-12 23:09:42 +090066 scheduleImpending(task);
67 return;
68 }
69
70 if (task.date().getTime() < head().date().getTime()) {
71 impendingTimer.cancel();
72 impendingTask.cancel();
73 TimerChainTask prevImpendingTask = pop().copy();
74 taskQueue.offer(prevImpendingTask);
75
76 scheduleImpending(task);
77 } else {
78 taskQueue.offer(task);
79 }
80 }
81 }
82
83 /**
84 * Schedule impending timer task.
85 * @param task impending timer chain task
86 * @return timer chain task
87 */
88 private TimerChainTask scheduleImpending(TimerChainTask task) {
89 taskQueue.offer(task);
90 Timer timer = new Timer();
91 this.setImpendingTask(task);
92 this.setImpendingTimer(timer);
93 timer.schedule(task, task.date());
94 return task;
95 }
96
97 /**
98 * Gets impending timer.
99 * @return impending timer
100 */
101 public Timer implendingTimer() {
102 return impendingTimer;
103 }
104
105 /**
106 * Sets impending timer.
107 * @param impendingTimer impending timer
108 */
109 public void setImpendingTimer(Timer impendingTimer) {
110 this.impendingTimer = impendingTimer;
111 }
112
113 /**
114 * Gets impending timer task.
115 * @return impending timer task
116 */
117 public TimerTask impendingTask() {
118 return impendingTask;
119 }
120
121 /**
122 * Sets impending timer task.
123 * @param impendingTask impending timer task
124 */
125 public void setImpendingTask(TimerChainTask impendingTask) {
126 this.impendingTask = impendingTask;
127 }
128
129 /**
130 * Gets head of timer chain task queue.
131 * @return timer chain task
132 */
133 public TimerChainTask head() {
jaegonkime0f45b52018-10-09 20:23:26 +0900134 if (!taskQueue.isEmpty()) {
jaegonkim6a7b5242018-09-12 23:09:42 +0900135 return taskQueue.peek();
136 } else {
137 return null;
138 }
139 }
140
141 /**
142 * Pops head of timer chain task queue.
143 * @return timer chain task
144 */
145 public TimerChainTask pop() {
jaegonkime0f45b52018-10-09 20:23:26 +0900146 if (!taskQueue.isEmpty()) {
jaegonkim6a7b5242018-09-12 23:09:42 +0900147 return taskQueue.poll();
148 } else {
149 return null;
150 }
151 }
152
153 /**
154 * Class for timer chain task.
155 */
156 public static class TimerChainTask extends TimerTask implements Comparable<TimerChainTask> {
157
158 private final TimerChain timerchain;
159 private final Date date;
160 private final Runnable runnable;
161
162 /**
163 * Constructor of timer chain task.
164 * @param timerchain timer chain
165 * @param date date to be scheduled
166 * @param runnable runnable to be executed by timer
167 */
168 public TimerChainTask(TimerChain timerchain, Date date, Runnable runnable) {
169 this.timerchain = timerchain;
170 this.date = date;
171 this.runnable = runnable;
172 }
173
174 /**
175 * Gets date.
176 * @return date of timer chain task
177 */
178 public Date date() {
179 return this.date;
180 }
181
182 /**
183 * Gets runnable.
184 * @return runnable of timer chain task
185 */
186 public Runnable runnable() {
187 return this.runnable;
188 }
189
190 @Override
191 public void run() {
192
193 TimerChainTask nextTask;
194 synchronized (timerchain) {
195 if (timerchain.impendingTask() != this) {
jaegonkim6a7b5242018-09-12 23:09:42 +0900196 runnable().run();
197 return;
198 }
199
200 timerchain.implendingTimer().cancel();
201 timerchain.pop();
202
203 nextTask = timerchain.head();
204
205 if (nextTask != null) {
206 Timer nextTimer = new Timer();
207 this.timerchain.setImpendingTask(nextTask);
208 this.timerchain.setImpendingTimer(nextTimer);
209 nextTimer.schedule(nextTask, nextTask.date());
210 }
211 }
212
213 runnable().run();
214
215 }
216
217 @Override
218 public int compareTo(TimerChainTask target) {
219 return date().compareTo(target.date());
220 }
221
Ray Milkeyfe6afd82018-11-26 14:03:20 -0800222 @Override
223 public boolean equals(Object o) {
224 if (this == o) {
225 return true;
226 }
227 if (!(o instanceof TimerChainTask)) {
228 return false;
229 }
230 TimerChainTask that = (TimerChainTask) o;
231
232 return this.date().equals(that.date());
233 }
234
235 @Override
236 public int hashCode() {
237 return Objects.hash(date);
238 }
239
jaegonkim6a7b5242018-09-12 23:09:42 +0900240 /**
241 * Copies timer chain task.
242 * @return timer chain task
243 */
244 public TimerChainTask copy() {
245 return new TimerChainTask(timerchain, date, runnable);
246 }
247 }
248}