blob: 79ee96c736e4f920aac9031a560bf942f5ad9c9a [file] [log] [blame]
Jian Li1b4cb332016-03-02 16:32:51 -08001/*
2 * Copyright 2016 Open Networking Laboratory
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 */
16
17package org.onlab.util;
18
Jian Li66f15262016-03-03 11:18:40 -080019import com.google.common.base.Throwables;
Jian Li1b4cb332016-03-02 16:32:51 -080020import org.slf4j.Logger;
21
22import java.util.Collection;
23import java.util.List;
24import java.util.concurrent.Callable;
25import java.util.concurrent.ExecutionException;
26import java.util.concurrent.Future;
27import java.util.concurrent.ScheduledExecutorService;
28import java.util.concurrent.ScheduledFuture;
29import java.util.concurrent.TimeUnit;
30import java.util.concurrent.TimeoutException;
31
32import static org.slf4j.LoggerFactory.getLogger;
33
34/**
35 * A new scheduled executor service that does not eat exception.
36 */
Jian Lia1d7f272016-03-28 17:21:47 -070037public class SharedScheduledExecutorService implements ScheduledExecutorService {
Jian Li1b4cb332016-03-02 16:32:51 -080038
39 private static final String NOT_ALLOWED = "Shutdown of scheduled executor is not allowed";
40 private final Logger log = getLogger(getClass());
41
42 private ScheduledExecutorService executor;
43
44 /**
45 * Creates a wrapper for the given scheduled executor service.
46 *
47 * @param executor executor service to wrap
48 */
Jian Li66f15262016-03-03 11:18:40 -080049 SharedScheduledExecutorService(ScheduledExecutorService executor) {
Jian Li1b4cb332016-03-02 16:32:51 -080050 this.executor = executor;
51 }
52
53 /**
54 * Returns the backing scheduled executor service.
55 *
56 * @return backing executor service
57 */
58 ScheduledExecutorService backingExecutor() {
59 return executor;
60 }
61
62 /**
63 * Swaps the backing executor with a new one and shuts down the old one.
64 *
Jian Lia1d7f272016-03-28 17:21:47 -070065 * @param executorService new scheduled executor service
Jian Li1b4cb332016-03-02 16:32:51 -080066 */
Jian Lia1d7f272016-03-28 17:21:47 -070067 void setBackingExecutor(ScheduledExecutorService executorService) {
Jian Li1b4cb332016-03-02 16:32:51 -080068 ScheduledExecutorService oldExecutor = this.executor;
Jian Lia1d7f272016-03-28 17:21:47 -070069 this.executor = executorService;
Jian Li1b4cb332016-03-02 16:32:51 -080070 oldExecutor.shutdown();
71 }
72
Jian Lia1d7f272016-03-28 17:21:47 -070073 /**
74 * Creates and executes a one-shot action that becomes enabled
75 * after the given delay.
76 *
77 * @param command the task to execute
78 * @param delay the time from now to delay execution
79 * @param unit the time unit of the delay parameter
80 * @param repeatFlag the flag to denote whether to restart a failed task
81 * @return a ScheduledFuture representing pending completion of
82 * the task and whose {@code get()} method will return
83 * {@code null} upon completion
84 */
85 public ScheduledFuture<?> schedule(Runnable command, long delay,
86 TimeUnit unit, boolean repeatFlag) {
87 return executor.schedule(wrap(command, repeatFlag), delay, unit);
88 }
89
Jian Li1b4cb332016-03-02 16:32:51 -080090 @Override
91 public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
Jian Lia1d7f272016-03-28 17:21:47 -070092 return schedule(command, delay, unit, false);
Jian Li1b4cb332016-03-02 16:32:51 -080093 }
94
95 @Override
96 public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
97 return executor.schedule(() -> {
98 V v = null;
99 try {
100 v = callable.call();
101 } catch (Exception e) {
102 log.error("Uncaught exception on " + callable.getClass(), e);
103 }
104 return v;
105 }, delay, unit);
106 }
107
Jian Lia1d7f272016-03-28 17:21:47 -0700108 /**
109 * Creates and executes a periodic action that becomes enabled first
110 * after the given initial delay, and subsequently with the given
111 * period; that is executions will commence after
112 * {@code initialDelay} then {@code initialDelay+period}, then
113 * {@code initialDelay + 2 * period}, and so on.
114 * Depends on the repeat flag that the user set, the failed tasks can be
115 * either restarted or terminated. If the repeat flag is set to to true,
116 * ant execution of the task encounters an exception, subsequent executions
117 * are permitted, otherwise, subsequent executions are suppressed.
118 * If any execution of this task takes longer than its period, then
119 * subsequent executions may start late, but will not concurrently execute.
120 *
121 * @param command the task to execute
122 * @param initialDelay the time to delay first execution
123 * @param period the period between successive executions
124 * @param unit the time unit of the initialDelay and period parameters
125 * @param repeatFlag the flag to denote whether to restart a failed task
126 * @return a ScheduledFuture representing pending completion of
127 * the task, and whose {@code get()} method will throw an
128 * exception upon cancellation
129 */
130 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
131 long initialDelay,
132 long period,
133 TimeUnit unit,
134 boolean repeatFlag) {
135 return executor.scheduleAtFixedRate(wrap(command, repeatFlag),
136 initialDelay, period, unit);
137 }
138
Jian Li1b4cb332016-03-02 16:32:51 -0800139 @Override
140 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
141 long period, TimeUnit unit) {
Jian Lia1d7f272016-03-28 17:21:47 -0700142 return scheduleAtFixedRate(command, initialDelay, period, unit, false);
143 }
144
145 /**
146 * Creates and executes a periodic action that becomes enabled first
147 * after the given initial delay, and subsequently with the
148 * given delay between the termination of one execution and the
149 * commencement of the next.
150 * Depends on the repeat flag that the user set, the failed tasks can be
151 * either restarted or terminated. If the repeat flag is set to to true,
152 * ant execution of the task encounters an exception, subsequent executions
153 * are permitted, otherwise, subsequent executions are suppressed.
154 *
155 * @param command the task to execute
156 * @param initialDelay the time to delay first execution
157 * @param delay the delay between the termination of one
158 * execution and the commencement of the next
159 * @param unit the time unit of the initialDelay and delay parameters
160 * @param repeatFlag the flag to denote whether to restart a failed task
161 * @return a ScheduledFuture representing pending completion of
162 * the task, and whose {@code get()} method will throw an
163 * exception upon cancellation
164 */
165 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
166 long initialDelay,
167 long delay,
168 TimeUnit unit,
169 boolean repeatFlag) {
170 return executor.scheduleWithFixedDelay(wrap(command, repeatFlag),
171 initialDelay, delay, unit);
Jian Li1b4cb332016-03-02 16:32:51 -0800172 }
173
174 @Override
175 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
176 long delay, TimeUnit unit) {
Jian Lia1d7f272016-03-28 17:21:47 -0700177 return scheduleWithFixedDelay(command, initialDelay, delay, unit, false);
Jian Li1b4cb332016-03-02 16:32:51 -0800178 }
179
180 @Override
181 public void shutdown() {
182 throw new UnsupportedOperationException(NOT_ALLOWED);
183 }
184
185 @Override
186 public List<Runnable> shutdownNow() {
187 throw new UnsupportedOperationException(NOT_ALLOWED);
188 }
189
190 @Override
191 public boolean isShutdown() {
192 return executor.isShutdown();
193 }
194
195 @Override
196 public boolean isTerminated() {
197 return executor.isTerminated();
198 }
199
200 @Override
201 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
202 return executor.awaitTermination(timeout, unit);
203 }
204
205 @Override
206 public <T> Future<T> submit(Callable<T> task) {
207 return executor.submit(task);
208 }
209
210 @Override
211 public <T> Future<T> submit(Runnable task, T result) {
212 return executor.submit(task, result);
213 }
214
215 @Override
216 public Future<?> submit(Runnable task) {
217 return executor.submit(task);
218 }
219
220 @Override
221 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
222 throws InterruptedException {
223 return executor.invokeAll(tasks);
224 }
225
226 @Override
227 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
228 long timeout, TimeUnit unit)
229 throws InterruptedException {
230 return executor.invokeAll(tasks, timeout, unit);
231 }
232
233 @Override
234 public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
235 throws InterruptedException, ExecutionException {
236 return executor.invokeAny(tasks);
237 }
238
239 @Override
240 public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
241 long timeout, TimeUnit unit) throws InterruptedException,
242 ExecutionException, TimeoutException {
243 return executor.invokeAny(tasks, timeout, unit);
244 }
245
246 @Override
247 public void execute(Runnable command) {
248 executor.execute(command);
249 }
250
Jian Lia1d7f272016-03-28 17:21:47 -0700251 private Runnable wrap(Runnable command, boolean repeatFlag) {
252 return new LoggableRunnable(command, repeatFlag);
Jian Li1b4cb332016-03-02 16:32:51 -0800253 }
254
255 /**
256 * A runnable class that allows to capture and log the exceptions.
257 */
258 private class LoggableRunnable implements Runnable {
259 private Runnable runnable;
Jian Lia1d7f272016-03-28 17:21:47 -0700260 private boolean repeatFlag;
Jian Li1b4cb332016-03-02 16:32:51 -0800261
Jian Lia1d7f272016-03-28 17:21:47 -0700262 public LoggableRunnable(Runnable runnable, boolean repeatFlag) {
Jian Li1b4cb332016-03-02 16:32:51 -0800263 super();
264 this.runnable = runnable;
Jian Lia1d7f272016-03-28 17:21:47 -0700265 this.repeatFlag = repeatFlag;
Jian Li1b4cb332016-03-02 16:32:51 -0800266 }
267
268 @Override
269 public void run() {
Jian Lia1d7f272016-03-28 17:21:47 -0700270 if (Thread.currentThread().isInterrupted()) {
271 log.info("Task interrupted, quitting");
272 return;
273 }
274
Jian Li1b4cb332016-03-02 16:32:51 -0800275 try {
276 runnable.run();
277 } catch (Exception e) {
278 log.error("Uncaught exception on " + runnable.getClass().getSimpleName(), e);
Jian Lia1d7f272016-03-28 17:21:47 -0700279
280 // if repeat flag set as false, we simply throw an exception to
281 // terminate this task
282 if (!repeatFlag) {
283 throw Throwables.propagate(e);
284 }
Jian Li1b4cb332016-03-02 16:32:51 -0800285 }
286 }
287 }
288}