blob: 257f98e5a2562186e8f699ceef4c93de9e951568 [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
19import org.slf4j.Logger;
20
21import java.util.Collection;
22import java.util.List;
23import java.util.concurrent.Callable;
24import java.util.concurrent.ExecutionException;
25import java.util.concurrent.Future;
26import java.util.concurrent.ScheduledExecutorService;
27import java.util.concurrent.ScheduledFuture;
28import java.util.concurrent.TimeUnit;
29import java.util.concurrent.TimeoutException;
30
31import static org.slf4j.LoggerFactory.getLogger;
32
33/**
34 * A new scheduled executor service that does not eat exception.
35 */
36class LogScheduledExecutorService implements ScheduledExecutorService {
37
38 private static final String NOT_ALLOWED = "Shutdown of scheduled executor is not allowed";
39 private final Logger log = getLogger(getClass());
40
41 private ScheduledExecutorService executor;
42
43 /**
44 * Creates a wrapper for the given scheduled executor service.
45 *
46 * @param executor executor service to wrap
47 */
48 LogScheduledExecutorService(ScheduledExecutorService executor) {
49 this.executor = executor;
50 }
51
52 /**
53 * Returns the backing scheduled executor service.
54 *
55 * @return backing executor service
56 */
57 ScheduledExecutorService backingExecutor() {
58 return executor;
59 }
60
61 /**
62 * Swaps the backing executor with a new one and shuts down the old one.
63 *
64 * @param executor new scheduled executor service
65 */
66 void setBackingExecutor(ScheduledExecutorService executor) {
67 ScheduledExecutorService oldExecutor = this.executor;
68 this.executor = executor;
69 oldExecutor.shutdown();
70 }
71
72 @Override
73 public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
74 return executor.schedule(wrap(command), delay, unit);
75 }
76
77 @Override
78 public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
79 return executor.schedule(() -> {
80 V v = null;
81 try {
82 v = callable.call();
83 } catch (Exception e) {
84 log.error("Uncaught exception on " + callable.getClass(), e);
85 }
86 return v;
87 }, delay, unit);
88 }
89
90 @Override
91 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
92 long period, TimeUnit unit) {
93 return executor.scheduleAtFixedRate(wrap(command), initialDelay, period, unit);
94 }
95
96 @Override
97 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
98 long delay, TimeUnit unit) {
99 return executor.scheduleWithFixedDelay(wrap(command), initialDelay, delay, unit);
100 }
101
102 @Override
103 public void shutdown() {
104 throw new UnsupportedOperationException(NOT_ALLOWED);
105 }
106
107 @Override
108 public List<Runnable> shutdownNow() {
109 throw new UnsupportedOperationException(NOT_ALLOWED);
110 }
111
112 @Override
113 public boolean isShutdown() {
114 return executor.isShutdown();
115 }
116
117 @Override
118 public boolean isTerminated() {
119 return executor.isTerminated();
120 }
121
122 @Override
123 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
124 return executor.awaitTermination(timeout, unit);
125 }
126
127 @Override
128 public <T> Future<T> submit(Callable<T> task) {
129 return executor.submit(task);
130 }
131
132 @Override
133 public <T> Future<T> submit(Runnable task, T result) {
134 return executor.submit(task, result);
135 }
136
137 @Override
138 public Future<?> submit(Runnable task) {
139 return executor.submit(task);
140 }
141
142 @Override
143 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
144 throws InterruptedException {
145 return executor.invokeAll(tasks);
146 }
147
148 @Override
149 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
150 long timeout, TimeUnit unit)
151 throws InterruptedException {
152 return executor.invokeAll(tasks, timeout, unit);
153 }
154
155 @Override
156 public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
157 throws InterruptedException, ExecutionException {
158 return executor.invokeAny(tasks);
159 }
160
161 @Override
162 public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
163 long timeout, TimeUnit unit) throws InterruptedException,
164 ExecutionException, TimeoutException {
165 return executor.invokeAny(tasks, timeout, unit);
166 }
167
168 @Override
169 public void execute(Runnable command) {
170 executor.execute(command);
171 }
172
173 private Runnable wrap(Runnable command) {
174 return new LoggableRunnable(command);
175 }
176
177 /**
178 * A runnable class that allows to capture and log the exceptions.
179 */
180 private class LoggableRunnable implements Runnable {
181 private Runnable runnable;
182
183 public LoggableRunnable(Runnable runnable) {
184 super();
185 this.runnable = runnable;
186 }
187
188 @Override
189 public void run() {
190 try {
191 runnable.run();
192 } catch (Exception e) {
193 log.error("Uncaught exception on " + runnable.getClass().getSimpleName(), e);
194 throw new RuntimeException(e);
195 }
196 }
197 }
198}